Versioning! With tests! Woo!
[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/;
c9d2e0a2 8use File::Spec;
7cb86b38 9require Module::Find;
a02675cd 10
41a6f8c0 11use base qw/DBIx::Class/;
a02675cd 12
0dc79249 13__PACKAGE__->mk_classdata('class_mappings' => {});
14__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 15__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 16__PACKAGE__->mk_classdata('storage');
82cc0386 17__PACKAGE__->mk_classdata('exception_action');
a02675cd 18
c2da098a 19=head1 NAME
20
21DBIx::Class::Schema - composable schemas
22
23=head1 SYNOPSIS
24
24d67825 25 package Library::Schema;
c2da098a 26 use base qw/DBIx::Class::Schema/;
bab77431 27
24d67825 28 # load Library::Schema::CD, Library::Schema::Book, Library::Schema::DVD
29 __PACKAGE__->load_classes(qw/CD Book DVD/);
c2da098a 30
24d67825 31 package Library::Schema::CD;
03312470 32 use base qw/DBIx::Class/;
77254782 33 __PACKAGE__->load_components(qw/PK::Auto Core/); # for example
24d67825 34 __PACKAGE__->table('cd');
c2da098a 35
5d9076f2 36 # Elsewhere in your code:
24d67825 37 my $schema1 = Library::Schema->connect(
a3d93194 38 $dsn,
39 $user,
40 $password,
24d67825 41 { AutoCommit => 0 },
a3d93194 42 );
bab77431 43
24d67825 44 my $schema2 = Library::Schema->connect($coderef_returning_dbh);
c2da098a 45
24d67825 46 # fetch objects using Library::Schema::DVD
47 my $resultset = $schema1->resultset('DVD')->search( ... );
48 my @dvd_objects = $schema2->resultset('DVD')->search( ... );
c2da098a 49
50=head1 DESCRIPTION
51
a3d93194 52Creates database classes based on a schema. This is the recommended way to
53use L<DBIx::Class> and allows you to use more than one concurrent connection
54with your classes.
429bd4f1 55
03312470 56NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
2053ab2a 57carefully, as DBIx::Class does things a little differently. Note in
03312470 58particular which module inherits off which.
59
c2da098a 60=head1 METHODS
61
87c4e602 62=head2 register_class
63
27f01d1f 64=over 4
65
ebc77b53 66=item Arguments: $moniker, $component_class
27f01d1f 67
68=back
076652e8 69
71f9df37 70Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
2053ab2a 71calling:
66d9ef6b 72
181a28f4 73 $schema->register_source($moniker, $component_class->result_source_instance);
076652e8 74
c2da098a 75=cut
76
a02675cd 77sub register_class {
0dc79249 78 my ($self, $moniker, $to_register) = @_;
79 $self->register_source($moniker => $to_register->result_source_instance);
74b92d9a 80}
81
87c4e602 82=head2 register_source
83
27f01d1f 84=over 4
85
ebc77b53 86=item Arguments: $moniker, $result_source
27f01d1f 87
88=back
076652e8 89
82b01c38 90Registers the L<DBIx::Class::ResultSource> in the schema with the given
91moniker.
076652e8 92
93=cut
94
0dc79249 95sub register_source {
96 my ($self, $moniker, $source) = @_;
97 my %reg = %{$self->source_registrations};
98 $reg{$moniker} = $source;
99 $self->source_registrations(\%reg);
100 $source->schema($self);
a917fb06 101 weaken($source->{schema}) if ref($self);
0dc79249 102 if ($source->result_class) {
103 my %map = %{$self->class_mappings};
104 $map{$source->result_class} = $moniker;
105 $self->class_mappings(\%map);
106 }
75d07914 107}
a02675cd 108
bfb2bd4f 109=head2 class
110
27f01d1f 111=over 4
82b01c38 112
ebc77b53 113=item Arguments: $moniker
27f01d1f 114
d601dc88 115=item Return Value: $classname
27f01d1f 116
117=back
82b01c38 118
2053ab2a 119Retrieves the result class name for the given moniker. For example:
82b01c38 120
121 my $class = $schema->class('CD');
bfb2bd4f 122
123=cut
124
125sub class {
0dc79249 126 my ($self, $moniker) = @_;
127 return $self->source($moniker)->result_class;
bfb2bd4f 128}
129
ea20d0fd 130=head2 source
131
27f01d1f 132=over 4
133
ebc77b53 134=item Arguments: $moniker
27f01d1f 135
d601dc88 136=item Return Value: $result_source
82b01c38 137
27f01d1f 138=back
82b01c38 139
24d67825 140 my $source = $schema->source('Book');
ea20d0fd 141
82b01c38 142Returns the L<DBIx::Class::ResultSource> object for the registered moniker.
ea20d0fd 143
144=cut
145
146sub source {
0dc79249 147 my ($self, $moniker) = @_;
148 my $sreg = $self->source_registrations;
149 return $sreg->{$moniker} if exists $sreg->{$moniker};
150
151 # if we got here, they probably passed a full class name
152 my $mapped = $self->class_mappings->{$moniker};
701da8c4 153 $self->throw_exception("Can't find source for ${moniker}")
0dc79249 154 unless $mapped && exists $sreg->{$mapped};
155 return $sreg->{$mapped};
ea20d0fd 156}
157
0dc79249 158=head2 sources
159
27f01d1f 160=over 4
161
d601dc88 162=item Return Value: @source_monikers
27f01d1f 163
164=back
82b01c38 165
166Returns the source monikers of all source registrations on this schema.
2053ab2a 167For example:
82b01c38 168
169 my @source_monikers = $schema->sources;
0dc79249 170
171=cut
172
173sub sources { return keys %{shift->source_registrations}; }
174
9b1ba0f2 175=head2 storage
176
177 my $storage = $schema->storage;
178
179Returns the L<DBIx::Class::Storage> object for this Schema.
180
ea20d0fd 181=head2 resultset
182
27f01d1f 183=over 4
184
ebc77b53 185=item Arguments: $moniker
27f01d1f 186
d601dc88 187=item Return Value: $result_set
82b01c38 188
27f01d1f 189=back
82b01c38 190
24d67825 191 my $rs = $schema->resultset('DVD');
ea20d0fd 192
82b01c38 193Returns the L<DBIx::Class::ResultSet> object for the registered moniker.
ea20d0fd 194
195=cut
196
197sub resultset {
0dc79249 198 my ($self, $moniker) = @_;
199 return $self->source($moniker)->resultset;
ea20d0fd 200}
201
87c4e602 202=head2 load_classes
203
27f01d1f 204=over 4
205
206=item Arguments: @classes?, { $namespace => [ @classes ] }+
207
208=back
076652e8 209
82b01c38 210With no arguments, this method uses L<Module::Find> to find all classes under
211the schema's namespace. Otherwise, this method loads the classes you specify
212(using L<use>), and registers them (using L</"register_class">).
076652e8 213
2053ab2a 214It is possible to comment out classes with a leading C<#>, but note that perl
215will think it's a mistake (trying to use a comment in a qw list), so you'll
216need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 217
2053ab2a 218Example:
82b01c38 219
220 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 221 # etc. (anything under the My::Schema namespace)
82b01c38 222
223 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
224 # not Other::Namespace::LinerNotes nor My::Schema::Track
225 My::Schema->load_classes(qw/ CD Artist #Track /, {
226 Other::Namespace => [qw/ Producer #LinerNotes /],
227 });
228
076652e8 229=cut
230
a02675cd 231sub load_classes {
5ce32fc1 232 my ($class, @params) = @_;
bab77431 233
5ce32fc1 234 my %comps_for;
bab77431 235
5ce32fc1 236 if (@params) {
237 foreach my $param (@params) {
238 if (ref $param eq 'ARRAY') {
239 # filter out commented entries
240 my @modules = grep { $_ !~ /^#/ } @$param;
bab77431 241
5ce32fc1 242 push (@{$comps_for{$class}}, @modules);
243 }
244 elsif (ref $param eq 'HASH') {
245 # more than one namespace possible
246 for my $comp ( keys %$param ) {
247 # filter out commented entries
248 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
249
250 push (@{$comps_for{$comp}}, @modules);
251 }
252 }
253 else {
254 # filter out commented entries
255 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
256 }
257 }
258 } else {
bc0c9800 259 my @comp = map { substr $_, length "${class}::" }
260 Module::Find::findallmod($class);
5ce32fc1 261 $comps_for{$class} = \@comp;
41a6f8c0 262 }
5ce32fc1 263
e6efde04 264 my @to_register;
265 {
266 no warnings qw/redefine/;
267 local *Class::C3::reinitialize = sub { };
268 foreach my $prefix (keys %comps_for) {
269 foreach my $comp (@{$comps_for{$prefix}||[]}) {
270 my $comp_class = "${prefix}::${comp}";
c037c03a 271 $class->ensure_class_loaded($comp_class);
bab77431 272 $comp_class->source_name($comp) unless $comp_class->source_name;
273
274 push(@to_register, [ $comp_class->source_name, $comp_class ]);
bfb2bd4f 275 }
5ce32fc1 276 }
a02675cd 277 }
e6efde04 278 Class::C3->reinitialize;
279
280 foreach my $to (@to_register) {
281 $class->register_class(@$to);
282 # if $class->can('result_source_instance');
283 }
a02675cd 284}
285
2374c5ff 286=head2 load_namespaces
287
288=over 4
289
85bd0538 290=item Arguments: %options?
2374c5ff 291
292=back
293
294This is an alternative to L</load_classes> above which assumes an alternative
c87014e8 295layout for automatic class loading. It assumes that all result
296classes are underneath a sub-namespace of the schema called C<Result>, any
7a58f051 297corresponding ResultSet classes are underneath a sub-namespace of the schema
46a05fd4 298called C<ResultSet>.
2374c5ff 299
46a05fd4 300Both of the sub-namespaces are configurable if you don't like the defaults,
c87014e8 301via the options C<result_namespace> and C<resultset_namespace>.
85bd0538 302
25fb14bd 303If (and only if) you specify the option C<default_resultset_class>, any found
c87014e8 304Result classes for which we do not find a corresponding
25fb14bd 305ResultSet class will have their C<resultset_class> set to
306C<default_resultset_class>.
0f4ec1d2 307
46a05fd4 308C<load_namespaces> takes care of calling C<resultset_class> for you where
309neccessary if you didn't do it for yourself.
f017c022 310
0f4ec1d2 311All of the namespace and classname options to this method are relative to
312the schema classname by default. To specify a fully-qualified name, prefix
313it with a literal C<+>.
2374c5ff 314
f017c022 315Examples:
2374c5ff 316
c87014e8 317 # load My::Schema::Result::CD, My::Schema::Result::Artist,
2374c5ff 318 # My::Schema::ResultSet::CD, etc...
0f4ec1d2 319 My::Schema->load_namespaces;
320
c87014e8 321 # Override everything to use ugly names.
322 # In this example, if there is a My::Schema::Res::Foo, but no matching
323 # My::Schema::RSets::Foo, then Foo will have its
324 # resultset_class set to My::Schema::RSetBase
0f4ec1d2 325 My::Schema->load_namespaces(
c87014e8 326 result_namespace => 'Res',
0f4ec1d2 327 resultset_namespace => 'RSets',
25fb14bd 328 default_resultset_class => 'RSetBase',
0f4ec1d2 329 );
2374c5ff 330
0f4ec1d2 331 # Put things in other namespaces
85bd0538 332 My::Schema->load_namespaces(
c87014e8 333 result_namespace => '+Some::Place::Results',
0f4ec1d2 334 resultset_namespace => '+Another::Place::RSets',
85bd0538 335 );
0f4ec1d2 336
f017c022 337If you'd like to use multiple namespaces of each type, simply use an arrayref
c87014e8 338of namespaces for that option. In the case that the same result
46a05fd4 339(or resultset) class exists in multiple namespaces, the latter entries in
340your list of namespaces will override earlier ones.
f017c022 341
342 My::Schema->load_namespaces(
c87014e8 343 # My::Schema::Results_C::Foo takes precedence over My::Schema::Results_B::Foo :
344 result_namespace => [ 'Results_A', 'Results_B', 'Results_C' ],
f017c022 345 resultset_namespace => [ '+Some::Place::RSets', 'RSets' ],
346 );
85bd0538 347
2374c5ff 348=cut
349
f017c022 350# Pre-pends our classname to the given relative classname or
351# class namespace, unless there is a '+' prefix, which will
7a58f051 352# be stripped.
f017c022 353sub _expand_relative_name {
7a58f051 354 my ($class, $name) = @_;
355 return if !$name;
356 $name = $class . '::' . $name if ! ($name =~ s/^\+//);
357 return $name;
f017c022 358}
359
360# returns a hash of $shortname => $fullname for every package
361# found in the given namespaces ($shortname is with the $fullname's
362# namespace stripped off)
363sub _map_namespaces {
364 my ($class, @namespaces) = @_;
365
366 my @results_hash;
367 foreach my $namespace (@namespaces) {
368 push(
369 @results_hash,
370 map { (substr($_, length "${namespace}::"), $_) }
371 Module::Find::findallmod($namespace)
372 );
373 }
374
375 @results_hash;
376}
377
2374c5ff 378sub load_namespaces {
85bd0538 379 my ($class, %args) = @_;
2374c5ff 380
c87014e8 381 my $result_namespace = delete $args{result_namespace} || 'Result';
25fb14bd 382 my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
25fb14bd 383 my $default_resultset_class = delete $args{default_resultset_class};
0f4ec1d2 384
25fb14bd 385 $class->throw_exception('load_namespaces: unknown option(s): '
386 . join(q{,}, map { qq{'$_'} } keys %args))
387 if scalar keys %args;
388
7a58f051 389 $default_resultset_class
390 = $class->_expand_relative_name($default_resultset_class);
f017c022 391
c87014e8 392 for my $arg ($result_namespace, $resultset_namespace) {
f017c022 393 $arg = [ $arg ] if !ref($arg) && $arg;
2374c5ff 394
f017c022 395 $class->throw_exception('load_namespaces: namespace arguments must be '
396 . 'a simple string or an arrayref')
397 if ref($arg) ne 'ARRAY';
2374c5ff 398
7a58f051 399 $_ = $class->_expand_relative_name($_) for (@$arg);
f017c022 400 }
2374c5ff 401
c87014e8 402 my %results = $class->_map_namespaces(@$result_namespace);
f017c022 403 my %resultsets = $class->_map_namespaces(@$resultset_namespace);
0f4ec1d2 404
2374c5ff 405 my @to_register;
406 {
25fb14bd 407 no warnings 'redefine';
2374c5ff 408 local *Class::C3::reinitialize = sub { };
25fb14bd 409 use warnings 'redefine';
0f4ec1d2 410
c87014e8 411 foreach my $result (keys %results) {
412 my $result_class = $results{$result};
413 $class->ensure_class_loaded($result_class);
414 $result_class->source_name($result) unless $result_class->source_name;
0f4ec1d2 415
c87014e8 416 my $rs_class = delete $resultsets{$result};
417 my $rs_set = $result_class->resultset_class;
25fb14bd 418 if($rs_set && $rs_set ne 'DBIx::Class::ResultSet') {
f017c022 419 if($rs_class && $rs_class ne $rs_set) {
c87014e8 420 warn "We found ResultSet class '$rs_class' for '$result', but it seems "
421 . "that you had already set '$result' to use '$rs_set' instead";
2374c5ff 422 }
423 }
25fb14bd 424 elsif($rs_class ||= $default_resultset_class) {
425 $class->ensure_class_loaded($rs_class);
c87014e8 426 $result_class->resultset_class($rs_class);
0f4ec1d2 427 }
2374c5ff 428
c87014e8 429 push(@to_register, [ $result_class->source_name, $result_class ]);
2374c5ff 430 }
431 }
432
0f4ec1d2 433 foreach (sort keys %resultsets) {
434 warn "load_namespaces found ResultSet class $_ with no "
c87014e8 435 . 'corresponding Result class';
2374c5ff 436 }
0f4ec1d2 437
fdcd8145 438 Class::C3->reinitialize;
439 $class->register_class(@$_) for (@to_register);
440
0f4ec1d2 441 return;
2374c5ff 442}
443
87c4e602 444=head2 compose_connection
445
27f01d1f 446=over 4
447
ebc77b53 448=item Arguments: $target_namespace, @db_info
429bd4f1 449
d601dc88 450=item Return Value: $new_schema
27f01d1f 451
452=back
076652e8 453
2053ab2a 454Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
455calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
456then injects the L<DBix::Class::ResultSetProxy> component and a
457resultset_instance classdata entry on all the new classes, in order to support
82b01c38 458$target_namespaces::$class->search(...) method calls.
459
460This is primarily useful when you have a specific need for class method access
461to a connection. In normal usage it is preferred to call
462L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
463on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
464more information.
54540863 465
076652e8 466=cut
467
a02675cd 468sub compose_connection {
ea20d0fd 469 my ($self, $target, @info) = @_;
80c90f5d 470 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 471 eval "require ${base};";
bc0c9800 472 $self->throw_exception
473 ("No arguments to load_classes and couldn't load ${base} ($@)")
474 if $@;
be381829 475
476 if ($self eq $target) {
477 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
478 foreach my $moniker ($self->sources) {
479 my $source = $self->source($moniker);
480 my $class = $source->result_class;
481 $self->inject_base($class, $base);
482 $class->mk_classdata(resultset_instance => $source->resultset);
483 $class->mk_classdata(class_resolver => $self);
484 }
50041f3c 485 $self->connection(@info);
be381829 486 return $self;
487 }
488
66d9ef6b 489 my $schema = $self->compose_namespace($target, $base);
ecceadff 490 {
491 no strict 'refs';
492 *{"${target}::schema"} = sub { $schema };
493 }
494
66d9ef6b 495 $schema->connection(@info);
0dc79249 496 foreach my $moniker ($schema->sources) {
497 my $source = $schema->source($moniker);
498 my $class = $source->result_class;
499 #warn "$moniker $class $source ".$source->storage;
8c49f629 500 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 501 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 502 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 503 }
504 return $schema;
e678398e 505}
506
77254782 507=head2 compose_namespace
508
27f01d1f 509=over 4
510
511=item Arguments: $target_namespace, $additional_base_class?
82b01c38 512
d601dc88 513=item Return Value: $new_schema
27f01d1f 514
515=back
13765dad 516
82b01c38 517For each L<DBIx::Class::ResultSource> in the schema, this method creates a
518class in the target namespace (e.g. $target_namespace::CD,
519$target_namespace::Artist) that inherits from the corresponding classes
520attached to the current schema.
77254782 521
82b01c38 522It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
523new $schema object. If C<$additional_base_class> is given, the new composed
524classes will inherit from first the corresponding classe from the current
525schema then the base class.
526
2053ab2a 527For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 528
529 $schema->compose_namespace('My::DB', 'Base::Class');
530 print join (', ', @My::DB::CD::ISA) . "\n";
531 print join (', ', @My::DB::Artist::ISA) ."\n";
532
2053ab2a 533will produce the output
82b01c38 534
535 My::Schema::CD, Base::Class
536 My::Schema::Artist, Base::Class
77254782 537
538=cut
539
e678398e 540sub compose_namespace {
66d9ef6b 541 my ($self, $target, $base) = @_;
542 my %reg = %{ $self->source_registrations };
11b78bd6 543 my %target;
544 my %map;
66d9ef6b 545 my $schema = $self->clone;
e9100ff7 546 {
547 no warnings qw/redefine/;
548 local *Class::C3::reinitialize = sub { };
549 foreach my $moniker ($schema->sources) {
550 my $source = $schema->source($moniker);
551 my $target_class = "${target}::${moniker}";
552 $self->inject_base(
553 $target_class => $source->result_class, ($base ? $base : ())
554 );
555 $source->result_class($target_class);
9d3d5af3 556 $target_class->result_source_instance($source)
557 if $target_class->can('result_source_instance');
e9100ff7 558 }
b7951443 559 }
e9100ff7 560 Class::C3->reinitialize();
11b78bd6 561 {
562 no strict 'refs';
1edaf6fe 563 foreach my $meth (qw/class source resultset/) {
564 *{"${target}::${meth}"} =
565 sub { shift->schema->$meth(@_) };
566 }
11b78bd6 567 }
bfb2bd4f 568 return $schema;
b7951443 569}
570
87c4e602 571=head2 setup_connection_class
572
27f01d1f 573=over 4
574
ebc77b53 575=item Arguments: $target, @info
27f01d1f 576
577=back
076652e8 578
82b01c38 579Sets up a database connection class to inject between the schema and the
580subclasses that the schema creates.
429bd4f1 581
076652e8 582=cut
583
b7951443 584sub setup_connection_class {
585 my ($class, $target, @info) = @_;
63e9583a 586 $class->inject_base($target => 'DBIx::Class::DB');
587 #$target->load_components('DB');
b7951443 588 $target->connection(@info);
589}
590
6b43ba5f 591=head2 storage_type
592
593=over 4
594
595=item Arguments: $storage_type
596
597=item Return Value: $storage_type
598
599=back
600
601Set the storage class that will be instantiated when L</connect> is called.
602If the classname starts with C<::>, the prefix C<DBIx::Class::Storage> is
603assumed by L</connect>. Defaults to C<::DBI>,
604which is L<DBIx::Class::Storage::DBI>.
605
606You want to use this to hardcoded subclasses of L<DBIx::Class::Storage::DBI>
607in cases where the appropriate subclass is not autodetected, such as when
608dealing with MSSQL via L<DBD::Sybase>, in which case you'd set it to
609C<::DBI::Sybase::MSSQL>.
610
87c4e602 611=head2 connection
612
27f01d1f 613=over 4
614
ebc77b53 615=item Arguments: @args
66d9ef6b 616
d601dc88 617=item Return Value: $new_schema
27f01d1f 618
619=back
82b01c38 620
621Instantiates a new Storage object of type
622L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
85f78622 623$storage->connect_info. Sets the connection in-place on the schema.
624
625See L<DBIx::Class::Storage::DBI/"connect_info"> for DBI-specific syntax,
626or L<DBIx::Class::Storage> in general.
66d9ef6b 627
628=cut
629
630sub connection {
631 my ($self, @info) = @_;
e59d3e5b 632 return $self if !@info && $self->storage;
1e10a11d 633 my $storage_class = $self->storage_type;
634 $storage_class = 'DBIx::Class::Storage'.$storage_class
635 if $storage_class =~ m/^::/;
8ef144ff 636 eval "require ${storage_class};";
bc0c9800 637 $self->throw_exception(
638 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
639 ) if $@;
82cc0386 640 my $storage = $storage_class->new($self);
66d9ef6b 641 $storage->connect_info(\@info);
642 $self->storage($storage);
c9d2e0a2 643 $self->on_connect() if($self->can('on_connect'));
66d9ef6b 644 return $self;
645}
646
87c4e602 647=head2 connect
648
27f01d1f 649=over 4
650
ebc77b53 651=item Arguments: @info
66d9ef6b 652
d601dc88 653=item Return Value: $new_schema
27f01d1f 654
655=back
82b01c38 656
657This is a convenience method. It is equivalent to calling
658$schema->clone->connection(@info). See L</connection> and L</clone> for more
659information.
66d9ef6b 660
661=cut
662
08b515f1 663sub connect { shift->clone->connection(@_) }
664
4012acd8 665=head2 txn_do
08b515f1 666
4012acd8 667=over 4
08b515f1 668
4012acd8 669=item Arguments: C<$coderef>, @coderef_args?
08b515f1 670
4012acd8 671=item Return Value: The return value of $coderef
08b515f1 672
4012acd8 673=back
08b515f1 674
4012acd8 675Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
676returning its result (if any). Equivalent to calling $schema->storage->txn_do.
677See L<DBIx::Class::Storage/"txn_do"> for more information.
08b515f1 678
4012acd8 679This interface is preferred over using the individual methods L</txn_begin>,
680L</txn_commit>, and L</txn_rollback> below.
08b515f1 681
4012acd8 682=cut
08b515f1 683
4012acd8 684sub txn_do {
685 my $self = shift;
08b515f1 686
4012acd8 687 $self->storage or $self->throw_exception
688 ('txn_do called on $schema without storage');
08b515f1 689
4012acd8 690 $self->storage->txn_do(@_);
691}
08b515f1 692
4012acd8 693=head2 txn_begin
a62cf8d4 694
4012acd8 695Begins a transaction (does nothing if AutoCommit is off). Equivalent to
696calling $schema->storage->txn_begin. See
697L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
27f01d1f 698
4012acd8 699=cut
82b01c38 700
4012acd8 701sub txn_begin {
702 my $self = shift;
27f01d1f 703
4012acd8 704 $self->storage or $self->throw_exception
705 ('txn_begin called on $schema without storage');
a62cf8d4 706
4012acd8 707 $self->storage->txn_begin;
708}
a62cf8d4 709
4012acd8 710=head2 txn_commit
a62cf8d4 711
4012acd8 712Commits the current transaction. Equivalent to calling
713$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
714for more information.
a62cf8d4 715
4012acd8 716=cut
a62cf8d4 717
4012acd8 718sub txn_commit {
719 my $self = shift;
a62cf8d4 720
4012acd8 721 $self->storage or $self->throw_exception
722 ('txn_commit called on $schema without storage');
a62cf8d4 723
4012acd8 724 $self->storage->txn_commit;
725}
70634260 726
4012acd8 727=head2 txn_rollback
a62cf8d4 728
4012acd8 729Rolls back the current transaction. Equivalent to calling
730$schema->storage->txn_rollback. See
731L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
a62cf8d4 732
733=cut
734
4012acd8 735sub txn_rollback {
736 my $self = shift;
a62cf8d4 737
19630353 738 $self->storage or $self->throw_exception
4012acd8 739 ('txn_rollback called on $schema without storage');
a62cf8d4 740
4012acd8 741 $self->storage->txn_rollback;
a62cf8d4 742}
743
66d9ef6b 744=head2 clone
745
27f01d1f 746=over 4
747
d601dc88 748=item Return Value: $new_schema
27f01d1f 749
750=back
82b01c38 751
66d9ef6b 752Clones the schema and its associated result_source objects and returns the
753copy.
754
755=cut
756
757sub clone {
758 my ($self) = @_;
04786a4c 759 my $clone = { (ref $self ? %$self : ()) };
760 bless $clone, (ref $self || $self);
761
66d9ef6b 762 foreach my $moniker ($self->sources) {
763 my $source = $self->source($moniker);
764 my $new = $source->new($source);
765 $clone->register_source($moniker => $new);
766 }
82cc0386 767 $clone->storage->set_schema($clone) if $clone->storage;
66d9ef6b 768 return $clone;
769}
770
87c4e602 771=head2 populate
772
27f01d1f 773=over 4
774
16c5f7d3 775=item Arguments: $source_name, \@data;
27f01d1f 776
777=back
a37a4697 778
16c5f7d3 779Pass this method a resultsource name, and an arrayref of
780arrayrefs. The arrayrefs should contain a list of column names,
781followed by one or many sets of matching data for the given columns.
782
744076d8 783In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
784to insert the data, as this is a fast method. However, insert_bulk currently
785assumes that your datasets all contain the same type of values, using scalar
786references in a column in one row, and not in another will probably not work.
787
788Otherwise, each set of data is inserted into the database using
16c5f7d3 789L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
790objects is returned.
82b01c38 791
792i.e.,
a37a4697 793
24d67825 794 $schema->populate('Artist', [
795 [ qw/artistid name/ ],
796 [ 1, 'Popular Band' ],
797 [ 2, 'Indie Band' ],
a62cf8d4 798 ...
799 ]);
a37a4697 800
801=cut
802
803sub populate {
804 my ($self, $name, $data) = @_;
805 my $rs = $self->resultset($name);
806 my @names = @{shift(@$data)};
54e0bd06 807 if(defined wantarray) {
808 my @created;
809 foreach my $item (@$data) {
810 my %create;
811 @create{@names} = @$item;
812 push(@created, $rs->create(\%create));
813 }
814 return @created;
a37a4697 815 }
54e0bd06 816 $self->storage->insert_bulk($self->source($name)->from, \@names, $data);
a37a4697 817}
818
82cc0386 819=head2 exception_action
820
821=over 4
822
823=item Arguments: $code_reference
824
825=back
826
db5dc233 827If C<exception_action> is set for this class/object, L</throw_exception>
828will prefer to call this code reference with the exception as an argument,
829rather than its normal <croak> action.
830
831Your subroutine should probably just wrap the error in the exception
832object/class of your choosing and rethrow. If, against all sage advice,
833you'd like your C<exception_action> to suppress a particular exception
834completely, simply have it return true.
82cc0386 835
836Example:
837
838 package My::Schema;
839 use base qw/DBIx::Class::Schema/;
840 use My::ExceptionClass;
841 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
842 __PACKAGE__->load_classes;
843
db5dc233 844 # or:
82cc0386 845 my $schema_obj = My::Schema->connect( .... );
846 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
847
db5dc233 848 # suppress all exceptions, like a moron:
849 $schema_obj->exception_action(sub { 1 });
850
5160b401 851=head2 throw_exception
701da8c4 852
75d07914 853=over 4
82b01c38 854
ebc77b53 855=item Arguments: $message
82b01c38 856
857=back
858
859Throws an exception. Defaults to using L<Carp::Clan> to report errors from
db5dc233 860user's perspective. See L</exception_action> for details on overriding
861this method's behavior.
701da8c4 862
863=cut
864
865sub throw_exception {
82cc0386 866 my $self = shift;
db5dc233 867 croak @_ if !$self->exception_action || !$self->exception_action->(@_);
701da8c4 868}
869
ec6704d4 870=head2 deploy (EXPERIMENTAL)
1c339d71 871
82b01c38 872=over 4
873
6e73ac25 874=item Arguments: $sqlt_args, $dir
82b01c38 875
876=back
877
878Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 879
880Note that this feature is currently EXPERIMENTAL and may not work correctly
881across all databases, or fully handle complex relationships.
1c339d71 882
51bace1c 883See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>. The most
884common value for this would be C<< { add_drop_table => 1, } >> to have the SQL
885produced include a DROP TABLE statement for each table created.
886
1c339d71 887=cut
888
889sub deploy {
6e73ac25 890 my ($self, $sqltargs, $dir) = @_;
1c339d71 891 $self->throw_exception("Can't deploy without storage") unless $self->storage;
6e73ac25 892 $self->storage->deploy($self, undef, $sqltargs, $dir);
1c339d71 893}
894
c0f61310 895=head2 create_ddl_dir (EXPERIMENTAL)
896
897=over 4
898
c9d2e0a2 899=item Arguments: \@databases, $version, $directory, $preversion, $sqlt_args
c0f61310 900
901=back
902
903Creates an SQL file based on the Schema, for each of the specified
c9d2e0a2 904database types, in the given directory. Given a previous version number,
905this will also create a file containing the ALTER TABLE statements to
906transform the previous schema into the current one. Note that these
907statements may contain DROP TABLE or DROP COLUMN statements that can
908potentially destroy data.
909
910The file names are created using the C<ddl_filename> method below, please
911override this method in your schema if you would like a different file
912name format. For the ALTER file, the same format is used, replacing
913$version in the name with "$preversion-$version".
914
915If no arguments are passed, then the following default values are used:
916
917=over 4
918
919=item databases - ['MySQL', 'SQLite', 'PostgreSQL']
920
921=item version - $schema->VERSION
922
923=item directory - './'
924
925=item preversion - <none>
926
927=back
c0f61310 928
929Note that this feature is currently EXPERIMENTAL and may not work correctly
930across all databases, or fully handle complex relationships.
931
c9d2e0a2 932WARNING: Please check all SQL files created, before applying them.
933
c0f61310 934=cut
935
6e73ac25 936sub create_ddl_dir {
e673f011 937 my $self = shift;
938
939 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
940 $self->storage->create_ddl_dir($self, @_);
941}
942
9b83fccd 943=head2 ddl_filename (EXPERIMENTAL)
944
c9d2e0a2 945=over 4
946
947=item Arguments: $directory, $database-type, $version, $preversion
948
949=back
950
951 my $filename = $table->ddl_filename($type, $dir, $version, $preversion)
952
953This method is called by C<create_ddl_dir> to compose a file name out of
954the supplied directory, database type and version number. The default file
955name format is: C<$dir$schema-$version-$type.sql>.
9b83fccd 956
c9d2e0a2 957You may override this method in your schema if you wish to use a different
958format.
9b83fccd 959
960=cut
961
6e73ac25 962sub ddl_filename {
c9d2e0a2 963 my ($self, $type, $dir, $version, $pversion) = @_;
e673f011 964
965 my $filename = ref($self);
9e7b9292 966 $filename =~ s/::/-/;
c9d2e0a2 967 $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql");
968 $filename =~ s/$version/$pversion-$version/ if($pversion);
e673f011 969
970 return $filename;
971}
972
a02675cd 9731;
c2da098a 974
c2da098a 975=head1 AUTHORS
976
daec44b8 977Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 978
979=head1 LICENSE
980
981You may distribute this code under the same terms as Perl itself.
982
983=cut