Add count_rs, move the code back from DBI - leave only sql specific hooks
[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;
ddc0a6c8 10use Sub::Name ();
7cb86b38 11require Module::Find;
a02675cd 12
41a6f8c0 13use base qw/DBIx::Class/;
a02675cd 14
0dc79249 15__PACKAGE__->mk_classdata('class_mappings' => {});
16__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 17__PACKAGE__->mk_classdata('storage_type' => '::DBI');
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
829517d4 32 # load all Result classes in Library/Schema/Result/
33 __PACKAGE__->load_namespaces();
c2da098a 34
829517d4 35 package Library::Schema::Result::CD;
03312470 36 use base qw/DBIx::Class/;
829517d4 37 __PACKAGE__->load_components(qw/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
829517d4 50 # fetch objects using Library::Schema::Result::DVD
24d67825 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
829517d4 64=head1 SETUP METHODS
c2da098a 65
829517d4 66=head2 load_namespaces
87c4e602 67
27f01d1f 68=over 4
69
829517d4 70=item Arguments: %options?
27f01d1f 71
72=back
076652e8 73
829517d4 74 __PACKAGE__->load_namespaces();
66d9ef6b 75
829517d4 76 __PACKAGE__->load_namespaces(
77 result_namespace => 'Res',
78 resultset_namespace => 'RSet',
79 default_resultset_class => '+MyDB::Othernamespace::RSet',
80 );
076652e8 81
829517d4 82With no arguments, this method uses L<Module::Find> to load all your
83Result classes from a sub-namespace F<Result> under your Schema class'
84namespace. Eg. With a Schema of I<MyDB::Schema> all files in
85I<MyDB::Schema::Result> are assumed to be Result classes.
c2da098a 86
829517d4 87It also finds all ResultSet classes in the namespace F<ResultSet> and
88loads them into the appropriate Result classes using for you. The
89matching is done by assuming the package name of the ResultSet class
90is the same as that of the Result class.
74b92d9a 91
672687db 92You will be warned if ResultSet classes are discovered for which there
829517d4 93are no matching Result classes like this:
87c4e602 94
829517d4 95 load_namespaces found ResultSet class $classname with no corresponding Result class
27f01d1f 96
829517d4 97If a Result class is found to already have a ResultSet class set using
98L</resultset_class> to some other class, you will be warned like this:
27f01d1f 99
829517d4 100 We found ResultSet class '$rs_class' for '$result', but it seems
101 that you had already set '$result' to use '$rs_set' instead
076652e8 102
829517d4 103Both of the sub-namespaces are configurable if you don't like the defaults,
104via the options C<result_namespace> and C<resultset_namespace>.
076652e8 105
829517d4 106If (and only if) you specify the option C<default_resultset_class>, any found
107Result classes for which we do not find a corresponding
108ResultSet class will have their C<resultset_class> set to
109C<default_resultset_class>.
076652e8 110
829517d4 111All of the namespace and classname options to this method are relative to
112the schema classname by default. To specify a fully-qualified name, prefix
113it with a literal C<+>.
2a4d9487 114
829517d4 115Examples:
2a4d9487 116
829517d4 117 # load My::Schema::Result::CD, My::Schema::Result::Artist,
118 # My::Schema::ResultSet::CD, etc...
119 My::Schema->load_namespaces;
2a4d9487 120
829517d4 121 # Override everything to use ugly names.
122 # In this example, if there is a My::Schema::Res::Foo, but no matching
123 # My::Schema::RSets::Foo, then Foo will have its
124 # resultset_class set to My::Schema::RSetBase
125 My::Schema->load_namespaces(
126 result_namespace => 'Res',
127 resultset_namespace => 'RSets',
128 default_resultset_class => 'RSetBase',
129 );
2a4d9487 130
829517d4 131 # Put things in other namespaces
132 My::Schema->load_namespaces(
133 result_namespace => '+Some::Place::Results',
134 resultset_namespace => '+Another::Place::RSets',
135 );
2a4d9487 136
829517d4 137If you'd like to use multiple namespaces of each type, simply use an arrayref
138of namespaces for that option. In the case that the same result
139(or resultset) class exists in multiple namespaces, the latter entries in
140your list of namespaces will override earlier ones.
2a4d9487 141
829517d4 142 My::Schema->load_namespaces(
143 # My::Schema::Results_C::Foo takes precedence over My::Schema::Results_B::Foo :
144 result_namespace => [ 'Results_A', 'Results_B', 'Results_C' ],
145 resultset_namespace => [ '+Some::Place::RSets', 'RSets' ],
146 );
2a4d9487 147
148=cut
149
829517d4 150# Pre-pends our classname to the given relative classname or
151# class namespace, unless there is a '+' prefix, which will
152# be stripped.
153sub _expand_relative_name {
154 my ($class, $name) = @_;
155 return if !$name;
156 $name = $class . '::' . $name if ! ($name =~ s/^\+//);
157 return $name;
2a4d9487 158}
159
f3405058 160# Finds all modules in the supplied namespace, or if omitted in the
161# namespace of $class. Untaints all findings as they can be assumed
162# to be safe
163sub _findallmod {
164 my $proto = shift;
165 my $ns = shift || ref $proto || $proto;
166
167 my @mods = Module::Find::findallmod($ns);
168
169 # try to untaint module names. mods where this fails
170 # are left alone so we don't have to change the old behavior
171 no locale; # localized \w doesn't untaint expression
172 return map { $_ =~ m/^( (?:\w+::)* \w+ )$/x ? $1 : $_ } @mods;
173}
174
829517d4 175# returns a hash of $shortname => $fullname for every package
b488020e 176# found in the given namespaces ($shortname is with the $fullname's
177# namespace stripped off)
829517d4 178sub _map_namespaces {
179 my ($class, @namespaces) = @_;
6eec9003 180
829517d4 181 my @results_hash;
182 foreach my $namespace (@namespaces) {
183 push(
184 @results_hash,
185 map { (substr($_, length "${namespace}::"), $_) }
f3405058 186 $class->_findallmod($namespace)
829517d4 187 );
0dc79249 188 }
27f01d1f 189
829517d4 190 @results_hash;
ea20d0fd 191}
192
b488020e 193# returns the result_source_instance for the passed class/object,
194# or dies with an informative message (used by load_namespaces)
195sub _ns_get_rsrc_instance {
196 my $class = shift;
197 my $rs = ref ($_[0]) || $_[0];
198
199 if ($rs->can ('result_source_instance') ) {
200 return $rs->result_source_instance;
201 }
202 else {
203 $class->throw_exception (
204 "Attempt to load_namespaces() class $rs failed - are you sure this is a real Result Class?"
205 );
206 }
207}
208
829517d4 209sub load_namespaces {
210 my ($class, %args) = @_;
0dc79249 211
829517d4 212 my $result_namespace = delete $args{result_namespace} || 'Result';
213 my $resultset_namespace = delete $args{resultset_namespace} || 'ResultSet';
214 my $default_resultset_class = delete $args{default_resultset_class};
0dc79249 215
829517d4 216 $class->throw_exception('load_namespaces: unknown option(s): '
217 . join(q{,}, map { qq{'$_'} } keys %args))
218 if scalar keys %args;
0dc79249 219
829517d4 220 $default_resultset_class
221 = $class->_expand_relative_name($default_resultset_class);
9b1ba0f2 222
829517d4 223 for my $arg ($result_namespace, $resultset_namespace) {
224 $arg = [ $arg ] if !ref($arg) && $arg;
9b1ba0f2 225
829517d4 226 $class->throw_exception('load_namespaces: namespace arguments must be '
227 . 'a simple string or an arrayref')
228 if ref($arg) ne 'ARRAY';
9b1ba0f2 229
829517d4 230 $_ = $class->_expand_relative_name($_) for (@$arg);
231 }
ea20d0fd 232
829517d4 233 my %results = $class->_map_namespaces(@$result_namespace);
234 my %resultsets = $class->_map_namespaces(@$resultset_namespace);
27f01d1f 235
829517d4 236 my @to_register;
237 {
238 no warnings 'redefine';
239 local *Class::C3::reinitialize = sub { };
240 use warnings 'redefine';
27f01d1f 241
3d27f771 242 # ensure classes are loaded and fetch properly sorted classes
243 $class->ensure_class_loaded($_) foreach(values %results);
244 my @subclass_last = sort { $results{$a}->isa($results{$b}) } keys(%results);
245
246 foreach my $result (@subclass_last) {
829517d4 247 my $result_class = $results{$result};
82b01c38 248
829517d4 249 my $rs_class = delete $resultsets{$result};
b488020e 250 my $rs_set = $class->_ns_get_rsrc_instance ($result_class)->resultset_class;
3d27f771 251
829517d4 252 if($rs_set && $rs_set ne 'DBIx::Class::ResultSet') {
3d27f771 253 if($rs_class && $rs_class ne $rs_set) {
341d5ede 254 carp "We found ResultSet class '$rs_class' for '$result', but it seems "
829517d4 255 . "that you had already set '$result' to use '$rs_set' instead";
256 }
257 }
258 elsif($rs_class ||= $default_resultset_class) {
259 $class->ensure_class_loaded($rs_class);
b488020e 260 $class->_ns_get_rsrc_instance ($result_class)->resultset_class($rs_class);
829517d4 261 }
82b01c38 262
b488020e 263 my $source_name = $class->_ns_get_rsrc_instance ($result_class)->source_name || $result;
0e6c5d58 264
265 push(@to_register, [ $source_name, $result_class ]);
829517d4 266 }
267 }
ea20d0fd 268
829517d4 269 foreach (sort keys %resultsets) {
341d5ede 270 carp "load_namespaces found ResultSet class $_ with no "
829517d4 271 . 'corresponding Result class';
272 }
ea20d0fd 273
829517d4 274 Class::C3->reinitialize;
275 $class->register_class(@$_) for (@to_register);
ea20d0fd 276
829517d4 277 return;
ea20d0fd 278}
279
87c4e602 280=head2 load_classes
281
27f01d1f 282=over 4
283
284=item Arguments: @classes?, { $namespace => [ @classes ] }+
285
286=back
076652e8 287
1ab61457 288L</load_classes> is an alternative method to L</load_namespaces>, both of
289which serve similar purposes, each with different advantages and disadvantages.
290In the general case you should use L</load_namespaces>, unless you need to
291be able to specify that only specific classes are loaded at runtime.
829517d4 292
82b01c38 293With no arguments, this method uses L<Module::Find> to find all classes under
294the schema's namespace. Otherwise, this method loads the classes you specify
295(using L<use>), and registers them (using L</"register_class">).
076652e8 296
2053ab2a 297It is possible to comment out classes with a leading C<#>, but note that perl
298will think it's a mistake (trying to use a comment in a qw list), so you'll
299need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 300
829517d4 301If any classes found do not appear to be Result class files, you will
302get the following warning:
303
304 Failed to load $comp_class. Can't find source_name method. Is
305 $comp_class really a full DBIC result class? Fix it, move it elsewhere,
306 or make your load_classes call more specific.
307
2053ab2a 308Example:
82b01c38 309
310 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 311 # etc. (anything under the My::Schema namespace)
82b01c38 312
313 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
314 # not Other::Namespace::LinerNotes nor My::Schema::Track
315 My::Schema->load_classes(qw/ CD Artist #Track /, {
316 Other::Namespace => [qw/ Producer #LinerNotes /],
317 });
318
076652e8 319=cut
320
a02675cd 321sub load_classes {
5ce32fc1 322 my ($class, @params) = @_;
bab77431 323
5ce32fc1 324 my %comps_for;
bab77431 325
5ce32fc1 326 if (@params) {
327 foreach my $param (@params) {
328 if (ref $param eq 'ARRAY') {
329 # filter out commented entries
330 my @modules = grep { $_ !~ /^#/ } @$param;
bab77431 331
5ce32fc1 332 push (@{$comps_for{$class}}, @modules);
333 }
334 elsif (ref $param eq 'HASH') {
335 # more than one namespace possible
336 for my $comp ( keys %$param ) {
337 # filter out commented entries
338 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
339
340 push (@{$comps_for{$comp}}, @modules);
341 }
342 }
343 else {
344 # filter out commented entries
345 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
346 }
347 }
348 } else {
bc0c9800 349 my @comp = map { substr $_, length "${class}::" }
f3405058 350 $class->_findallmod;
5ce32fc1 351 $comps_for{$class} = \@comp;
41a6f8c0 352 }
5ce32fc1 353
e6efde04 354 my @to_register;
355 {
356 no warnings qw/redefine/;
357 local *Class::C3::reinitialize = sub { };
358 foreach my $prefix (keys %comps_for) {
359 foreach my $comp (@{$comps_for{$prefix}||[]}) {
360 my $comp_class = "${prefix}::${comp}";
c037c03a 361 $class->ensure_class_loaded($comp_class);
bab77431 362
89271e56 363 my $snsub = $comp_class->can('source_name');
364 if(! $snsub ) {
341d5ede 365 carp "Failed to load $comp_class. Can't find source_name method. Is $comp_class really a full DBIC result class? Fix it, move it elsewhere, or make your load_classes call more specific.";
89271e56 366 next;
367 }
368 $comp = $snsub->($comp_class) || $comp;
369
93405cf0 370 push(@to_register, [ $comp, $comp_class ]);
bfb2bd4f 371 }
5ce32fc1 372 }
a02675cd 373 }
e6efde04 374 Class::C3->reinitialize;
375
376 foreach my $to (@to_register) {
377 $class->register_class(@$to);
378 # if $class->can('result_source_instance');
379 }
a02675cd 380}
381
829517d4 382=head2 storage_type
2374c5ff 383
384=over 4
385
829517d4 386=item Arguments: $storage_type|{$storage_type, \%args}
387
388=item Return value: $storage_type|{$storage_type, \%args}
389
390=item Default value: DBIx::Class::Storage::DBI
2374c5ff 391
392=back
393
829517d4 394Set the storage class that will be instantiated when L</connect> is called.
395If the classname starts with C<::>, the prefix C<DBIx::Class::Storage> is
396assumed by L</connect>.
2374c5ff 397
829517d4 398You want to use this to set subclasses of L<DBIx::Class::Storage::DBI>
399in cases where the appropriate subclass is not autodetected, such as
400when dealing with MSSQL via L<DBD::Sybase>, in which case you'd set it
401to C<::DBI::Sybase::MSSQL>.
85bd0538 402
829517d4 403If your storage type requires instantiation arguments, those are
404defined as a second argument in the form of a hashref and the entire
405value needs to be wrapped into an arrayref or a hashref. We support
406both types of refs here in order to play nice with your
407Config::[class] or your choice. See
408L<DBIx::Class::Storage::DBI::Replicated> for an example of this.
0f4ec1d2 409
829517d4 410=head2 exception_action
f017c022 411
829517d4 412=over 4
0f4ec1d2 413
829517d4 414=item Arguments: $code_reference
f017c022 415
829517d4 416=item Return value: $code_reference
85bd0538 417
829517d4 418=item Default value: None
2374c5ff 419
829517d4 420=back
f017c022 421
829517d4 422If C<exception_action> is set for this class/object, L</throw_exception>
423will prefer to call this code reference with the exception as an argument,
424rather than L<DBIx::Class::Exception/throw>.
f017c022 425
829517d4 426Your subroutine should probably just wrap the error in the exception
427object/class of your choosing and rethrow. If, against all sage advice,
428you'd like your C<exception_action> to suppress a particular exception
429completely, simply have it return true.
f017c022 430
829517d4 431Example:
f017c022 432
829517d4 433 package My::Schema;
434 use base qw/DBIx::Class::Schema/;
435 use My::ExceptionClass;
436 __PACKAGE__->exception_action(sub { My::ExceptionClass->throw(@_) });
437 __PACKAGE__->load_classes;
2374c5ff 438
829517d4 439 # or:
440 my $schema_obj = My::Schema->connect( .... );
441 $schema_obj->exception_action(sub { My::ExceptionClass->throw(@_) });
0f4ec1d2 442
829517d4 443 # suppress all exceptions, like a moron:
444 $schema_obj->exception_action(sub { 1 });
25fb14bd 445
829517d4 446=head2 stacktrace
f017c022 447
829517d4 448=over 4
2374c5ff 449
829517d4 450=item Arguments: boolean
2374c5ff 451
829517d4 452=back
2374c5ff 453
829517d4 454Whether L</throw_exception> should include stack trace information.
455Defaults to false normally, but defaults to true if C<$ENV{DBIC_TRACE}>
456is true.
0f4ec1d2 457
829517d4 458=head2 sqlt_deploy_hook
0f4ec1d2 459
829517d4 460=over
0f4ec1d2 461
829517d4 462=item Arguments: $sqlt_schema
2374c5ff 463
829517d4 464=back
2374c5ff 465
829517d4 466An optional sub which you can declare in your own Schema class that will get
467passed the L<SQL::Translator::Schema> object when you deploy the schema via
468L</create_ddl_dir> or L</deploy>.
0f4ec1d2 469
829517d4 470For an example of what you can do with this, see
471L<DBIx::Class::Manual::Cookbook/Adding Indexes And Functions To Your SQL>.
fdcd8145 472
2d7d8459 473Note that sqlt_deploy_hook is called by L</deployment_statements>, which in turn
474is called before L</deploy>. Therefore the hook can be used only to manipulate
475the L<SQL::Translator::Schema> object before it is turned into SQL fed to the
476database. If you want to execute post-deploy statements which can not be generated
477by L<SQL::Translator>, the currently suggested method is to overload L</deploy>
478and use L<dbh_do|DBIx::Class::Storage::DBI/dbh_do>.
479
829517d4 480=head1 METHODS
2374c5ff 481
829517d4 482=head2 connect
87c4e602 483
27f01d1f 484=over 4
485
829517d4 486=item Arguments: @connectinfo
429bd4f1 487
d601dc88 488=item Return Value: $new_schema
27f01d1f 489
490=back
076652e8 491
829517d4 492Creates and returns a new Schema object. The connection info set on it
493is used to create a new instance of the storage backend and set it on
494the Schema object.
1c133e22 495
829517d4 496See L<DBIx::Class::Storage::DBI/"connect_info"> for DBI-specific
5d52945a 497syntax on the C<@connectinfo> argument, or L<DBIx::Class::Storage> in
829517d4 498general.
1c133e22 499
5d52945a 500Note that C<connect_info> expects an arrayref of arguments, but
501C<connect> does not. C<connect> wraps it's arguments in an arrayref
502before passing them to C<connect_info>.
503
4c7d99ca 504=head3 Overloading
505
506C<connect> is a convenience method. It is equivalent to calling
507$schema->clone->connection(@connectinfo). To write your own overloaded
508version, overload L</connection> instead.
509
076652e8 510=cut
511
829517d4 512sub connect { shift->clone->connection(@_) }
e678398e 513
829517d4 514=head2 resultset
77254782 515
27f01d1f 516=over 4
517
829517d4 518=item Arguments: $source_name
82b01c38 519
829517d4 520=item Return Value: $resultset
27f01d1f 521
522=back
13765dad 523
829517d4 524 my $rs = $schema->resultset('DVD');
82b01c38 525
829517d4 526Returns the L<DBIx::Class::ResultSet> object for the registered source
527name.
77254782 528
529=cut
530
829517d4 531sub resultset {
532 my ($self, $moniker) = @_;
533 return $self->source($moniker)->resultset;
b7951443 534}
535
829517d4 536=head2 sources
6b43ba5f 537
538=over 4
539
829517d4 540=item Return Value: @source_names
6b43ba5f 541
542=back
543
829517d4 544 my @source_names = $schema->sources;
6b43ba5f 545
829517d4 546Lists names of all the sources registered on this Schema object.
6b43ba5f 547
829517d4 548=cut
161fb223 549
829517d4 550sub sources { return keys %{shift->source_registrations}; }
106d5f3b 551
829517d4 552=head2 source
87c4e602 553
27f01d1f 554=over 4
555
829517d4 556=item Arguments: $source_name
66d9ef6b 557
829517d4 558=item Return Value: $result_source
27f01d1f 559
560=back
82b01c38 561
829517d4 562 my $source = $schema->source('Book');
85f78622 563
829517d4 564Returns the L<DBIx::Class::ResultSource> object for the registered
565source name.
66d9ef6b 566
567=cut
568
829517d4 569sub source {
570 my ($self, $moniker) = @_;
571 my $sreg = $self->source_registrations;
572 return $sreg->{$moniker} if exists $sreg->{$moniker};
573
574 # if we got here, they probably passed a full class name
575 my $mapped = $self->class_mappings->{$moniker};
576 $self->throw_exception("Can't find source for ${moniker}")
577 unless $mapped && exists $sreg->{$mapped};
578 return $sreg->{$mapped};
161fb223 579}
580
829517d4 581=head2 class
87c4e602 582
27f01d1f 583=over 4
584
829517d4 585=item Arguments: $source_name
66d9ef6b 586
829517d4 587=item Return Value: $classname
27f01d1f 588
589=back
82b01c38 590
829517d4 591 my $class = $schema->class('CD');
592
593Retrieves the Result class name for the given source name.
66d9ef6b 594
595=cut
596
829517d4 597sub class {
598 my ($self, $moniker) = @_;
599 return $self->source($moniker)->result_class;
600}
08b515f1 601
4012acd8 602=head2 txn_do
08b515f1 603
4012acd8 604=over 4
08b515f1 605
4012acd8 606=item Arguments: C<$coderef>, @coderef_args?
08b515f1 607
4012acd8 608=item Return Value: The return value of $coderef
08b515f1 609
4012acd8 610=back
08b515f1 611
4012acd8 612Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
613returning its result (if any). Equivalent to calling $schema->storage->txn_do.
614See L<DBIx::Class::Storage/"txn_do"> for more information.
08b515f1 615
4012acd8 616This interface is preferred over using the individual methods L</txn_begin>,
617L</txn_commit>, and L</txn_rollback> below.
08b515f1 618
281719d2 619WARNING: If you are connected with C<AutoCommit => 0> the transaction is
620considered nested, and you will still need to call L</txn_commit> to write your
621changes when appropriate. You will also want to connect with C<auto_savepoint =>
6221> to get partial rollback to work, if the storage driver for your database
623supports it.
624
625Connecting with C<AutoCommit => 1> is recommended.
626
4012acd8 627=cut
08b515f1 628
4012acd8 629sub txn_do {
630 my $self = shift;
08b515f1 631
4012acd8 632 $self->storage or $self->throw_exception
633 ('txn_do called on $schema without storage');
08b515f1 634
4012acd8 635 $self->storage->txn_do(@_);
636}
66d9ef6b 637
6936e902 638=head2 txn_scope_guard
75c8a7ab 639
89028f42 640Runs C<txn_scope_guard> on the schema's storage. See
641L<DBIx::Class::Storage/txn_scope_guard>.
75c8a7ab 642
b85be4c1 643=cut
644
1bc193ac 645sub txn_scope_guard {
646 my $self = shift;
647
648 $self->storage or $self->throw_exception
649 ('txn_scope_guard called on $schema without storage');
650
651 $self->storage->txn_scope_guard(@_);
652}
653
4012acd8 654=head2 txn_begin
a62cf8d4 655
4012acd8 656Begins a transaction (does nothing if AutoCommit is off). Equivalent to
657calling $schema->storage->txn_begin. See
658L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
27f01d1f 659
4012acd8 660=cut
82b01c38 661
4012acd8 662sub txn_begin {
663 my $self = shift;
27f01d1f 664
4012acd8 665 $self->storage or $self->throw_exception
666 ('txn_begin called on $schema without storage');
a62cf8d4 667
4012acd8 668 $self->storage->txn_begin;
669}
a62cf8d4 670
4012acd8 671=head2 txn_commit
a62cf8d4 672
4012acd8 673Commits the current transaction. Equivalent to calling
674$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
675for more information.
a62cf8d4 676
4012acd8 677=cut
a62cf8d4 678
4012acd8 679sub txn_commit {
680 my $self = shift;
a62cf8d4 681
4012acd8 682 $self->storage or $self->throw_exception
683 ('txn_commit called on $schema without storage');
a62cf8d4 684
4012acd8 685 $self->storage->txn_commit;
686}
70634260 687
4012acd8 688=head2 txn_rollback
a62cf8d4 689
4012acd8 690Rolls back the current transaction. Equivalent to calling
691$schema->storage->txn_rollback. See
692L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
a62cf8d4 693
694=cut
695
4012acd8 696sub txn_rollback {
697 my $self = shift;
a62cf8d4 698
19630353 699 $self->storage or $self->throw_exception
4012acd8 700 ('txn_rollback called on $schema without storage');
a62cf8d4 701
4012acd8 702 $self->storage->txn_rollback;
a62cf8d4 703}
704
829517d4 705=head2 storage
66d9ef6b 706
829517d4 707 my $storage = $schema->storage;
04786a4c 708
829517d4 709Returns the L<DBIx::Class::Storage> object for this Schema. Grab this
710if you want to turn on SQL statement debugging at runtime, or set the
711quote character. For the default storage, the documentation can be
712found in L<DBIx::Class::Storage::DBI>.
66d9ef6b 713
87c4e602 714=head2 populate
715
27f01d1f 716=over 4
717
16c5f7d3 718=item Arguments: $source_name, \@data;
27f01d1f 719
829517d4 720=item Return value: \@$objects | nothing
721
27f01d1f 722=back
a37a4697 723
16c5f7d3 724Pass this method a resultsource name, and an arrayref of
725arrayrefs. The arrayrefs should contain a list of column names,
726followed by one or many sets of matching data for the given columns.
727
744076d8 728In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
729to insert the data, as this is a fast method. However, insert_bulk currently
730assumes that your datasets all contain the same type of values, using scalar
731references in a column in one row, and not in another will probably not work.
732
733Otherwise, each set of data is inserted into the database using
16c5f7d3 734L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
735objects is returned.
82b01c38 736
737i.e.,
a37a4697 738
24d67825 739 $schema->populate('Artist', [
740 [ qw/artistid name/ ],
741 [ 1, 'Popular Band' ],
742 [ 2, 'Indie Band' ],
a62cf8d4 743 ...
744 ]);
5a93e138 745
746Since wantarray context is basically the same as looping over $rs->create(...)
747you won't see any performance benefits and in this case the method is more for
748convenience. Void context sends the column information directly to storage
749using <DBI>s bulk insert method. So the performance will be much better for
750storages that support this method.
751
752Because of this difference in the way void context inserts rows into your
753database you need to note how this will effect any loaded components that
754override or augment insert. For example if you are using a component such
755as L<DBIx::Class::UUIDColumns> to populate your primary keys you MUST use
756wantarray context if you want the PKs automatically created.
a37a4697 757
758=cut
759
760sub populate {
761 my ($self, $name, $data) = @_;
c4e67d31 762 if(my $rs = $self->resultset($name)) {
763 if(defined wantarray) {
764 return $rs->populate($data);
765 } else {
766 $rs->populate($data);
54e0bd06 767 }
c4e67d31 768 } else {
769 $self->throw_exception("$name is not a resultset");
8b93a938 770 }
a37a4697 771}
772
829517d4 773=head2 connection
774
775=over 4
776
777=item Arguments: @args
778
779=item Return Value: $new_schema
780
781=back
782
783Similar to L</connect> except sets the storage object and connection
784data in-place on the Schema class. You should probably be calling
785L</connect> to get a proper Schema object instead.
786
4c7d99ca 787=head3 Overloading
788
789Overload C<connection> to change the behaviour of C<connect>.
829517d4 790
791=cut
792
793sub connection {
794 my ($self, @info) = @_;
795 return $self if !@info && $self->storage;
796
797 my ($storage_class, $args) = ref $self->storage_type ?
798 ($self->_normalize_storage_type($self->storage_type),{}) : ($self->storage_type, {});
799
800 $storage_class = 'DBIx::Class::Storage'.$storage_class
801 if $storage_class =~ m/^::/;
802 eval "require ${storage_class};";
803 $self->throw_exception(
804 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
805 ) if $@;
806 my $storage = $storage_class->new($self=>$args);
807 $storage->connect_info(\@info);
808 $self->storage($storage);
809 return $self;
810}
811
812sub _normalize_storage_type {
813 my ($self, $storage_type) = @_;
814 if(ref $storage_type eq 'ARRAY') {
815 return @$storage_type;
816 } elsif(ref $storage_type eq 'HASH') {
817 return %$storage_type;
818 } else {
819 $self->throw_exception('Unsupported REFTYPE given: '. ref $storage_type);
820 }
821}
822
823=head2 compose_namespace
82cc0386 824
825=over 4
826
829517d4 827=item Arguments: $target_namespace, $additional_base_class?
828
829=item Retur Value: $new_schema
830
831=back
832
833For each L<DBIx::Class::ResultSource> in the schema, this method creates a
834class in the target namespace (e.g. $target_namespace::CD,
835$target_namespace::Artist) that inherits from the corresponding classes
836attached to the current schema.
837
838It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
839new $schema object. If C<$additional_base_class> is given, the new composed
840classes will inherit from first the corresponding classe from the current
841schema then the base class.
842
843For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
844
845 $schema->compose_namespace('My::DB', 'Base::Class');
846 print join (', ', @My::DB::CD::ISA) . "\n";
847 print join (', ', @My::DB::Artist::ISA) ."\n";
848
849will produce the output
850
851 My::Schema::CD, Base::Class
852 My::Schema::Artist, Base::Class
853
854=cut
855
856# this might be oversimplified
857# sub compose_namespace {
858# my ($self, $target, $base) = @_;
859
860# my $schema = $self->clone;
861# foreach my $moniker ($schema->sources) {
862# my $source = $schema->source($moniker);
863# my $target_class = "${target}::${moniker}";
864# $self->inject_base(
865# $target_class => $source->result_class, ($base ? $base : ())
866# );
867# $source->result_class($target_class);
868# $target_class->result_source_instance($source)
869# if $target_class->can('result_source_instance');
870# $schema->register_source($moniker, $source);
871# }
872# return $schema;
873# }
874
875sub compose_namespace {
876 my ($self, $target, $base) = @_;
877 my $schema = $self->clone;
878 {
879 no warnings qw/redefine/;
880# local *Class::C3::reinitialize = sub { };
881 foreach my $moniker ($schema->sources) {
882 my $source = $schema->source($moniker);
883 my $target_class = "${target}::${moniker}";
884 $self->inject_base(
885 $target_class => $source->result_class, ($base ? $base : ())
886 );
887 $source->result_class($target_class);
888 $target_class->result_source_instance($source)
889 if $target_class->can('result_source_instance');
890 $schema->register_source($moniker, $source);
891 }
892 }
893# Class::C3->reinitialize();
894 {
895 no strict 'refs';
896 no warnings 'redefine';
897 foreach my $meth (qw/class source resultset/) {
898 *{"${target}::${meth}"} =
899 sub { shift->schema->$meth(@_) };
900 }
901 }
902 return $schema;
903}
904
905sub setup_connection_class {
906 my ($class, $target, @info) = @_;
907 $class->inject_base($target => 'DBIx::Class::DB');
908 #$target->load_components('DB');
909 $target->connection(@info);
910}
911
912=head2 svp_begin
913
914Creates a new savepoint (does nothing outside a transaction).
915Equivalent to calling $schema->storage->svp_begin. See
916L<DBIx::Class::Storage::DBI/"svp_begin"> for more information.
917
918=cut
919
920sub svp_begin {
921 my ($self, $name) = @_;
922
923 $self->storage or $self->throw_exception
924 ('svp_begin called on $schema without storage');
925
926 $self->storage->svp_begin($name);
927}
928
929=head2 svp_release
930
931Releases a savepoint (does nothing outside a transaction).
932Equivalent to calling $schema->storage->svp_release. See
933L<DBIx::Class::Storage::DBI/"svp_release"> for more information.
934
935=cut
936
937sub svp_release {
938 my ($self, $name) = @_;
939
940 $self->storage or $self->throw_exception
941 ('svp_release called on $schema without storage');
82cc0386 942
829517d4 943 $self->storage->svp_release($name);
944}
82cc0386 945
829517d4 946=head2 svp_rollback
db5dc233 947
829517d4 948Rollback to a savepoint (does nothing outside a transaction).
949Equivalent to calling $schema->storage->svp_rollback. See
950L<DBIx::Class::Storage::DBI/"svp_rollback"> for more information.
82cc0386 951
829517d4 952=cut
82cc0386 953
829517d4 954sub svp_rollback {
955 my ($self, $name) = @_;
82cc0386 956
829517d4 957 $self->storage or $self->throw_exception
958 ('svp_rollback called on $schema without storage');
82cc0386 959
829517d4 960 $self->storage->svp_rollback($name);
961}
db5dc233 962
829517d4 963=head2 clone
613397e7 964
84c5863b 965=over 4
613397e7 966
829517d4 967=item Return Value: $new_schema
613397e7 968
969=back
970
829517d4 971Clones the schema and its associated result_source objects and returns the
972copy.
973
974=cut
975
976sub clone {
977 my ($self) = @_;
978 my $clone = { (ref $self ? %$self : ()) };
979 bless $clone, (ref $self || $self);
980
981 $clone->class_mappings({ %{$clone->class_mappings} });
982 $clone->source_registrations({ %{$clone->source_registrations} });
983 foreach my $moniker ($self->sources) {
984 my $source = $self->source($moniker);
985 my $new = $source->new($source);
986 # we use extra here as we want to leave the class_mappings as they are
987 # but overwrite the source_registrations entry with the new source
988 $clone->register_extra_source($moniker => $new);
989 }
990 $clone->storage->set_schema($clone) if $clone->storage;
991 return $clone;
992}
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
10976519 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
10976519 1026See L<SQL::Translator/METHODS> for a list of values for C<\%sqlt_args>.
1027The most common value for this would be C<< { add_drop_table => 1 } >>
1028to have the SQL produced include a C<DROP TABLE> statement for each table
1029created. For quoting purposes supply C<quote_table_names> and
3e82fc27 1030C<quote_field_names>.
51bace1c 1031
499adf63 1032Additionally, the DBIx::Class parser accepts a C<sources> parameter as a hash
1033ref or an array ref, containing a list of source to deploy. If present, then
0e2c6809 1034only the sources listed will get deployed. Furthermore, you can use the
1035C<add_fk_index> parser parameter to prevent the parser from creating an index for each
1036FK.
499adf63 1037
1c339d71 1038=cut
1039
1040sub deploy {
6e73ac25 1041 my ($self, $sqltargs, $dir) = @_;
1c339d71 1042 $self->throw_exception("Can't deploy without storage") unless $self->storage;
6e73ac25 1043 $self->storage->deploy($self, undef, $sqltargs, $dir);
1c339d71 1044}
1045
0e0ce6c1 1046=head2 deployment_statements
1047
1048=over 4
1049
10976519 1050=item Arguments: See L<DBIx::Class::Storage::DBI/deployment_statements>
0e0ce6c1 1051
829517d4 1052=item Return value: $listofstatements
1053
0e0ce6c1 1054=back
1055
10976519 1056A convenient shortcut to
1057C<< $self->storage->deployment_statements($self, @args) >>.
1058Returns the SQL statements used by L</deploy> and
1059L<DBIx::Class::Schema::Storage/deploy>.
0e0ce6c1 1060
1061=cut
1062
1063sub deployment_statements {
7ad93f5a 1064 my $self = shift;
0e0ce6c1 1065
1066 $self->throw_exception("Can't generate deployment statements without a storage")
1067 if not $self->storage;
1068
7ad93f5a 1069 $self->storage->deployment_statements($self, @_);
0e0ce6c1 1070}
1071
c0f61310 1072=head2 create_ddl_dir (EXPERIMENTAL)
1073
1074=over 4
1075
10976519 1076=item Arguments: See L<DBIx::Class::Storage::DBI/create_ddl_dir>
c0f61310 1077
1078=back
1079
10976519 1080A convenient shortcut to
1081C<< $self->storage->create_ddl_dir($self, @args) >>.
c9d2e0a2 1082
10976519 1083Creates an SQL file based on the Schema, for each of the specified
1084database types, in the given directory.
c9d2e0a2 1085
c0f61310 1086=cut
1087
6e73ac25 1088sub create_ddl_dir {
e673f011 1089 my $self = shift;
1090
1091 $self->throw_exception("Can't create_ddl_dir without storage") unless $self->storage;
1092 $self->storage->create_ddl_dir($self, @_);
1093}
1094
e63a82f7 1095=head2 ddl_filename
9b83fccd 1096
c9d2e0a2 1097=over 4
1098
99a74c4a 1099=item Arguments: $database-type, $version, $directory, $preversion
c9d2e0a2 1100
829517d4 1101=item Return value: $normalised_filename
1102
c9d2e0a2 1103=back
1104
99a74c4a 1105 my $filename = $table->ddl_filename($type, $version, $dir, $preversion)
c9d2e0a2 1106
1107This method is called by C<create_ddl_dir> to compose a file name out of
1108the supplied directory, database type and version number. The default file
1109name format is: C<$dir$schema-$version-$type.sql>.
9b83fccd 1110
c9d2e0a2 1111You may override this method in your schema if you wish to use a different
1112format.
9b83fccd 1113
1114=cut
1115
6e73ac25 1116sub ddl_filename {
99a74c4a 1117 my ($self, $type, $version, $dir, $preversion) = @_;
e673f011 1118
99a74c4a 1119 my $filename = ref($self);
1120 $filename =~ s/::/-/g;
1121 $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql");
1122 $filename =~ s/$version/$preversion-$version/ if($preversion);
1123
1124 return $filename;
e673f011 1125}
1126
4146e3da 1127=head2 thaw
1128
829517d4 1129Provided as the recommended way of thawing schema objects. You can call
4146e3da 1130C<Storable::thaw> directly if you wish, but the thawed objects will not have a
1131reference to any schema, so are rather useless
1132
1133=cut
1134
1135sub thaw {
1136 my ($self, $obj) = @_;
1137 local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1138 return Storable::thaw($obj);
1139}
1140
1141=head2 freeze
1142
1143This doesn't actualy do anything more than call L<Storable/freeze>, it is just
1144provided here for symetry.
1145
d2f3e87b 1146=cut
1147
4146e3da 1148sub freeze {
1149 return Storable::freeze($_[1]);
1150}
1151
1152=head2 dclone
1153
1154Recommeneded way of dcloning objects. This is needed to properly maintain
1155references to the schema object (which itself is B<not> cloned.)
1156
1157=cut
1158
1159sub dclone {
1160 my ($self, $obj) = @_;
1161 local $DBIx::Class::ResultSourceHandle::thaw_schema = $self;
1162 return Storable::dclone($obj);
1163}
1164
93e4d41a 1165=head2 schema_version
1166
829517d4 1167Returns the current schema class' $VERSION in a normalised way.
93e4d41a 1168
1169=cut
1170
1171sub schema_version {
1172 my ($self) = @_;
1173 my $class = ref($self)||$self;
1174
1175 # does -not- use $schema->VERSION
1176 # since that varies in results depending on if version.pm is installed, and if
1177 # so the perl or XS versions. If you want this to change, bug the version.pm
1178 # author to make vpp and vxs behave the same.
1179
1180 my $version;
1181 {
1182 no strict 'refs';
1183 $version = ${"${class}::VERSION"};
1184 }
1185 return $version;
1186}
1187
829517d4 1188
1189=head2 register_class
1190
1191=over 4
1192
1193=item Arguments: $moniker, $component_class
1194
1195=back
1196
1197This method is called by L</load_namespaces> and L</load_classes> to install the found classes into your Schema. You should be using those instead of this one.
1198
1199You will only need this method if you have your Result classes in
1200files which are not named after the packages (or all in the same
1201file). You may also need it to register classes at runtime.
1202
1203Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
1204calling:
1205
1206 $schema->register_source($moniker, $component_class->result_source_instance);
1207
1208=cut
1209
1210sub register_class {
1211 my ($self, $moniker, $to_register) = @_;
1e36ef62 1212 $self->register_source($moniker => $to_register->result_source_instance);
829517d4 1213}
1214
1215=head2 register_source
1216
1217=over 4
1218
1219=item Arguments: $moniker, $result_source
1220
1221=back
1222
1223This method is called by L</register_class>.
1224
1225Registers the L<DBIx::Class::ResultSource> in the schema with the given
1226moniker.
1227
1228=cut
1229
1230sub register_source {
1231 my $self = shift;
1232
1233 $self->_register_source(@_);
1234}
1235
1236=head2 register_extra_source
1237
1238=over 4
1239
1240=item Arguments: $moniker, $result_source
1241
1242=back
1243
1244As L</register_source> but should be used if the result class already
1245has a source and you want to register an extra one.
1246
1247=cut
1248
1249sub register_extra_source {
1250 my $self = shift;
1251
1252 $self->_register_source(@_, { extra => 1 });
1253}
1254
1255sub _register_source {
1256 my ($self, $moniker, $source, $params) = @_;
1257
6d4f9d94 1258 my $orig_source = $source;
2461ae19 1259
0e6c5d58 1260 $source = $source->new({ %$source, source_name => $moniker });
2461ae19 1261 $source->schema($self);
1262 weaken($source->{schema}) if ref($self);
1263
1264 my $rs_class = $source->result_class;
829517d4 1265
1266 my %reg = %{$self->source_registrations};
1267 $reg{$moniker} = $source;
1268 $self->source_registrations(\%reg);
1269
829517d4 1270 return if ($params->{extra});
5dfe40b8 1271 return unless defined($rs_class) && $rs_class->can('result_source_instance');
829517d4 1272
2461ae19 1273 my %map = %{$self->class_mappings};
f18d2d04 1274 if (
1275 exists $map{$rs_class}
1276 and
1277 $map{$rs_class} ne $moniker
1278 and
1279 $rs_class->result_source_instance ne $orig_source
1280 ) {
2461ae19 1281 carp "$rs_class already has a source, use register_extra_source for additional sources";
829517d4 1282 }
2461ae19 1283 $map{$rs_class} = $moniker;
1284 $self->class_mappings(\%map);
829517d4 1285}
1286
1287sub _unregister_source {
1288 my ($self, $moniker) = @_;
1289 my %reg = %{$self->source_registrations};
1290
1291 my $source = delete $reg{$moniker};
1292 $self->source_registrations(\%reg);
1293 if ($source->result_class) {
1294 my %map = %{$self->class_mappings};
1295 delete $map{$source->result_class};
1296 $self->class_mappings(\%map);
1297 }
1298}
1299
1300
1301=head2 compose_connection (DEPRECATED)
1302
1303=over 4
1304
1305=item Arguments: $target_namespace, @db_info
1306
1307=item Return Value: $new_schema
1308
1309=back
1310
1311DEPRECATED. You probably wanted compose_namespace.
1312
1313Actually, you probably just wanted to call connect.
1314
1315=begin hidden
1316
1317(hidden due to deprecation)
1318
1319Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
1320calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
1321then injects the L<DBix::Class::ResultSetProxy> component and a
1322resultset_instance classdata entry on all the new classes, in order to support
1323$target_namespaces::$class->search(...) method calls.
1324
1325This is primarily useful when you have a specific need for class method access
1326to a connection. In normal usage it is preferred to call
1327L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
1328on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
1329more information.
1330
1331=end hidden
1332
1333=cut
1334
1335{
1336 my $warn;
1337
1338 sub compose_connection {
1339 my ($self, $target, @info) = @_;
1340
341d5ede 1341 carp "compose_connection deprecated as of 0.08000"
829517d4 1342 unless ($INC{"DBIx/Class/CDBICompat.pm"} || $warn++);
1343
1344 my $base = 'DBIx::Class::ResultSetProxy';
1345 eval "require ${base};";
1346 $self->throw_exception
1347 ("No arguments to load_classes and couldn't load ${base} ($@)")
1348 if $@;
1349
1350 if ($self eq $target) {
1351 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
1352 foreach my $moniker ($self->sources) {
1353 my $source = $self->source($moniker);
1354 my $class = $source->result_class;
1355 $self->inject_base($class, $base);
1356 $class->mk_classdata(resultset_instance => $source->resultset);
1357 $class->mk_classdata(class_resolver => $self);
1358 }
1359 $self->connection(@info);
1360 return $self;
1361 }
1362
1363 my $schema = $self->compose_namespace($target, $base);
1364 {
1365 no strict 'refs';
1366 my $name = join '::', $target, 'schema';
1367 *$name = Sub::Name::subname $name, sub { $schema };
1368 }
1369
1370 $schema->connection(@info);
1371 foreach my $moniker ($schema->sources) {
1372 my $source = $schema->source($moniker);
1373 my $class = $source->result_class;
1374 #warn "$moniker $class $source ".$source->storage;
1375 $class->mk_classdata(result_source_instance => $source);
1376 $class->mk_classdata(resultset_instance => $source->resultset);
1377 $class->mk_classdata(class_resolver => $schema);
1378 }
1379 return $schema;
1380 }
1381}
1382
a02675cd 13831;
c2da098a 1384
c2da098a 1385=head1 AUTHORS
1386
daec44b8 1387Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 1388
1389=head1 LICENSE
1390
1391You may distribute this code under the same terms as Perl itself.
1392
1393=cut