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