Add loader_roles option
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader.pm
CommitLineData
18fca96a 1package DBIx::Class::Schema::Loader;
a78e3fed 2
3use strict;
a4a19f3c 4use warnings;
65e705c3 5use base qw/DBIx::Class::Schema Class::Accessor::Grouped/;
cc15b78f 6use MRO::Compat;
942bd5e0 7use mro 'c3';
39d5612f 8use Carp::Clan qw/^DBIx::Class/;
9use Scalar::Util 'weaken';
ecf22f0a 10use Sub::Util 'set_subname';
7ba9582a 11use DBIx::Class::Schema::Loader::Utils qw/array_eq sigwarn_silencer/;
23fd9773 12use Try::Tiny;
f3bed1f1 13use curry;
39d5612f 14use namespace::clean;
3980d69c 15
a4a19f3c 16# Always remember to do all digits for the version even if they're 0
17# i.e. first release of 0.XX *must* be 0.XX000. This avoids fBSD ports
18# brain damage and presumably various other packaging systems too
188038c0 19our $VERSION = '0.07048';
457eb8a6 20
65e705c3 21__PACKAGE__->mk_group_accessors('inherited', qw/
22 _loader_args
23 dump_to_dir
24 _loader_invoked
25 _loader
26 loader_class
9f869cd6 27 loader_roles
65e705c3 28 naming
f22644d7 29 use_namespaces
a8d229ff 30/);
65e705c3 31__PACKAGE__->_loader_args({});
a78e3fed 32
50799170 33=encoding UTF-8
41bc1375 34
a78e3fed 35=head1 NAME
36
227cea92 37DBIx::Class::Schema::Loader - Create a DBIx::Class::Schema based on a database
a78e3fed 38
39=head1 SYNOPSIS
40
83bce685 41 ### use this module to generate a set of class files
42
43 # in a script
44 use DBIx::Class::Schema::Loader qw/ make_schema_at /;
45 make_schema_at(
46 'My::Schema',
47 { debug => 1,
48 dump_directory => './lib',
49 },
50 [ 'dbi:Pg:dbname="foo"', 'myuser', 'mypassword',
51 { loader_class => 'MyLoader' } # optionally
52 ],
53 );
54
55 # from the command line or a shell script with dbicdump (distributed
56 # with this module). Do `perldoc dbicdump` for usage.
57 dbicdump -o dump_directory=./lib \
58 -o components='["InflateColumn::DateTime"]' \
59 -o debug=1 \
60 My::Schema \
61 'dbi:Pg:dbname=foo' \
62 myuser \
63 mypassword
64
65 ### or generate and load classes at runtime
66 # note: this technique is not recommended
67 # for use in production code
68
69 package My::Schema;
70 use base qw/DBIx::Class::Schema::Loader/;
71
72 __PACKAGE__->loader_options(
73 constraint => '^foo.*',
74 # debug => 1,
75 );
76
77 #### in application code elsewhere:
78
79 use My::Schema;
80
81 my $schema1 = My::Schema->connect( $dsn, $user, $password, $attrs);
82 # -or-
83 my $schema1 = "My::Schema"; $schema1->connection(as above);
074e81cd 84
41bc1375 85=head1 DESCRIPTION
074e81cd 86
fbd83464 87DBIx::Class::Schema::Loader automates the definition of a
227cea92 88L<DBIx::Class::Schema> by scanning database table definitions and setting up
89the columns, primary keys, unique constraints and relationships.
a78e3fed 90
700658a5 91See L<dbicdump> for the C<dbicdump> utility.
92
227cea92 93DBIx::Class::Schema::Loader currently supports only the DBI storage type. It
1065db64 94has explicit support for L<DBD::Pg>, L<DBD::mysql>, L<DBD::DB2>,
227cea92 95L<DBD::Firebird>, L<DBD::InterBase>, L<DBD::Informix>, L<DBD::SQLAnywhere>,
6b0e47fc 96L<DBD::SQLite>, L<DBD::Sybase> (for Sybase ASE and MSSSQL), L<DBD::ODBC> (for
227cea92 97MSSQL, MSAccess, Firebird and SQL Anywhere) L<DBD::ADO> (for MSSQL and
98MSAccess) and L<DBD::Oracle>. Other DBI drivers may function to a greater or
6b0e47fc 99lesser degree with this loader, depending on how much of the DBI spec they
100implement, and how standard their implementation is.
3fe9c5d9 101
102Patches to make other DBDs work correctly welcome.
a78e3fed 103
996be9ee 104See L<DBIx::Class::Schema::Loader::DBI::Writing> for notes on writing
105your own vendor-specific subclass for an unsupported DBD driver.
a78e3fed 106
227cea92 107This module requires L<DBIx::Class> 0.08127 or later, and obsoletes the older
108L<DBIx::Class::Loader>.
89ecd854 109
227cea92 110See L<DBIx::Class::Schema::Loader::Base> for available options.
89ecd854 111
a78e3fed 112=head1 METHODS
113
39d5612f 114=head2 loader
115
227cea92 116The loader object, as class data on your Schema. For methods available see
117L<DBIx::Class::Schema::Loader::Base> and L<DBIx::Class::Schema::Loader::DBI>.
39d5612f 118
119=cut
120
121sub loader {
122 my $self = shift;
123 $self->_loader(@_);
124}
125
29ddb54c 126=head2 loader_class
127
530e0bf6 128=over 4
129
130=item Argument: $loader_class
131
132=back
133
29ddb54c 134Set the loader class to be instantiated when L</connection> is called.
135If the classname starts with "::", "DBIx::Class::Schema::Loader" is
136prepended. Defaults to L<DBIx::Class::Schema/storage_type> (which must
137start with "::" when using L<DBIx::Class::Schema::Loader>).
138
139This is mostly useful for subclassing existing loaders or in conjunction
140with L</dump_to_dir>.
141
996be9ee 142=head2 loader_options
a78e3fed 143
530e0bf6 144=over 4
145
146=item Argument: \%loader_options
147
148=back
149
996be9ee 150Example in Synopsis above demonstrates a few common arguments. For
151detailed information on all of the arguments, most of which are
152only useful in fairly complex scenarios, see the
153L<DBIx::Class::Schema::Loader::Base> documentation.
a78e3fed 154
3fe9c5d9 155If you intend to use C<loader_options>, you must call
156C<loader_options> before any connection is made, or embed the
157C<loader_options> in the connection information itself as shown
158below. Setting C<loader_options> after the connection has
59cfa251 159already been made is useless.
a78e3fed 160
996be9ee 161=cut
1031d4f6 162
996be9ee 163sub loader_options {
164 my $self = shift;
65e705c3 165
d65cda9e 166 my %args = (ref $_[0] eq 'HASH') ? %{$_[0]} : @_;
996be9ee 167 $self->_loader_args(\%args);
996be9ee 168
169 $self;
170}
171
172sub _invoke_loader {
173 my $self = shift;
174 my $class = ref $self || $self;
175
59cfa251 176 my $args = $self->_loader_args;
177
23fd9773 178 # temporarily copy $self's storage to class
179 my $class_storage = $class->storage;
180 if (ref $self) {
181 $class->storage($self->storage);
182 $class->storage->set_schema($class);
183 }
184
185 $args->{schema} = $class;
59cfa251 186 $args->{schema_class} = $class;
59cfa251 187 $args->{dump_directory} ||= $self->dump_to_dir;
a0e0a56a 188 $args->{naming} = $self->naming if $self->naming;
42ea7b88 189 $args->{use_namespaces} = $self->use_namespaces if defined $self->use_namespaces;
af6c2665 190
71a6e88a 191 my $loader_class = $self->loader_class;
192 if ($loader_class) {
193 $loader_class = "DBIx::Class::Schema::Loader${loader_class}" if $loader_class =~ /^::/;
194 $args->{loader_class} = $loader_class;
195 };
196
5939bf08 197 # XXX this only works for relative storage_type, like ::DBI ...
71a6e88a 198 my $impl = $loader_class || "DBIx::Class::Schema::Loader" . $self->storage_type;
23fd9773 199 try {
200 $self->ensure_class_loaded($impl)
201 }
202 catch {
203 croak qq/Could not load loader_class "$impl": "$_"/;
204 };
af6c2665 205
9f869cd6 206 my $loader = $impl->new(%$args);
207 if (my @roles = @{$self->loader_roles || []}) {
208 require Role::Tiny;
209 Role::Tiny->apply_roles_to_object($loader, @roles);
210 }
211
212 $class->loader($loader);
23fd9773 213 $class->loader->load;
214 $class->_loader_invoked(1);
996be9ee 215
23fd9773 216 # copy to $self
217 if (ref $self) {
218 $self->loader($class->loader);
219 $self->_loader_invoked(1);
220
221 $self->_merge_state_from($class);
222 }
223
224 # restore $class's storage
225 $class->storage($class_storage);
226
227 return $self;
228}
229
230# FIXME This needs to be moved into DBIC at some point, otherwise we are
231# maintaining things to do with DBIC guts, which we have no business of
232# maintaining. But at the moment it would be just dead code in DBIC, so we'll
233# maintain it here.
234sub _merge_state_from {
235 my ($self, $from) = @_;
236
237 my $orig_class_mappings = $self->class_mappings;
238 my $orig_source_registrations = $self->source_registrations;
239
240 $self->_copy_state_from($from);
241
7ba9582a 242 $self->class_mappings(__merge($orig_class_mappings, $self->class_mappings))
23fd9773 243 if $orig_class_mappings;
244
7ba9582a 245 $self->source_registrations(__merge($orig_source_registrations, $self->source_registrations))
23fd9773 246 if $orig_source_registrations;
247}
248
7ba9582a 249my $merger;
250sub __merge {
251
252 local $SIG{__WARN__} = sigwarn_silencer(qr/Arguments for _merge_hashes must be hash references/);
253
254 ( $merger ||= do {
255 require Hash::Merge;
256 my $m = Hash::Merge->new('LEFT_PRECEDENT');
257 $m->set_clone_behavior(0);
258 $m;
259 } )->merge(
260 $_[0], $_[1]
261 );
262}
263
23fd9773 264sub _copy_state_from {
265 my $self = shift;
266 my ($from) = @_;
267
268 # older DBIC's do not have this method
269 if (try { DBIx::Class->VERSION('0.08197'); 1 }) {
270 return $self->next::method(@_);
271 }
272 else {
273 # this is a copy from DBIC git master pre 0.08197
274 $self->class_mappings({ %{$from->class_mappings} });
275 $self->source_registrations({ %{$from->source_registrations} });
276
277 foreach my $moniker ($from->sources) {
278 my $source = $from->source($moniker);
279 my $new = $source->new($source);
280 # we use extra here as we want to leave the class_mappings as they are
281 # but overwrite the source_registrations entry with the new source
282 $self->register_extra_source($moniker => $new);
283 }
284
285 if ($from->storage) {
286 $self->storage($from->storage);
287 $self->storage->set_schema($self);
288 }
289 }
996be9ee 290}
291
292=head2 connection
293
530e0bf6 294=over 4
295
296=item Arguments: @args
297
298=item Return Value: $new_schema
299
300=back
301
302See L<DBIx::Class::Schema/connection> for basic usage.
d65cda9e 303
9f869cd6 304If the final argument is a hashref, and it contains the keys C<loader_options>,
305C<loader_class> or C<loader_roles>, those keys will be deleted, and their values
306value will be used for the loader options or class, respectively, just as if set
307via the L</loader_options> or L</loader_class> methods above.
d65cda9e 308
309The actual auto-loading operation (the heart of this module) will be invoked
310as soon as the connection information is defined.
996be9ee 311
312=cut
313
314sub connection {
de89deba 315 my $self = shift;
316 my $class = ref $self || $self;
d65cda9e 317
318 if($_[-1] && ref $_[-1] eq 'HASH') {
9f869cd6 319 for my $option (qw/loader_class loader_options loader_roles/) {
29ddb54c 320 if(my $value = delete $_[-1]->{$option}) {
321 $self->$option($value);
322 }
d65cda9e 323 }
29ddb54c 324 pop @_ if !keys %{$_[-1]};
d65cda9e 325 }
326
cc15b78f 327 # Make sure we inherit from schema_base_class and load schema_components
328 # before connecting.
329 require DBIx::Class::Schema::Loader::Base;
330 my $temp_loader = DBIx::Class::Schema::Loader::Base->new(
a2c2cf69 331 %{ $self->_loader_args },
332 schema => $self,
b7b8c970 333 naming => 'current',
334 use_namespaces => 1,
cc15b78f 335 );
336
50b95db6 337 my $modify_isa = 0;
338 my @components;
339
cc15b78f 340 if ($temp_loader->schema_base_class || $temp_loader->schema_components) {
50b95db6 341 @components = @{ $temp_loader->schema_components }
cc15b78f 342 if $temp_loader->schema_components;
343
344 push @components, ('+'.$temp_loader->schema_base_class)
345 if $temp_loader->schema_base_class;
346
50b95db6 347 my $class_isa = do {
348 no strict 'refs';
349 \@{"${class}::ISA"};
350 };
351
352 my @component_classes = map {
353 /^\+/ ? substr($_, 1, length($_) - 1) : "DBIx::Class::$_"
354 } @components;
355
356 $modify_isa++ if not array_eq([ @$class_isa[0..(@components-1)] ], \@component_classes)
357 }
358
359 if ($modify_isa) {
de89deba 360 $class->load_components(@components);
cc15b78f 361
a1781f7f 362 # This hack is necessary because we changed @ISA of $self through
de89deba 363 # ->load_components and we are now in a different place in the mro.
cc15b78f 364 no warnings 'redefine';
365
ecf22f0a 366 local *connection = set_subname __PACKAGE__.'::connection' => sub {
cc15b78f 367 my $self = shift;
368 $self->next::method(@_);
369 };
370
de89deba 371 my @linear_isa = @{ mro::get_linear_isa($class) };
372
373 my $next_method;
374
375 foreach my $i (1..$#linear_isa) {
376 no strict 'refs';
377 $next_method = *{$linear_isa[$i].'::connection'}{CODE};
378 last if $next_method;
379 }
380
381 $self = $self->$next_method(@_);
cc15b78f 382 }
a1781f7f 383 else {
384 $self = $self->next::method(@_);
385 }
996be9ee 386
59cfa251 387 if(!$class->_loader_invoked) {
fa994d3c 388 $self->_invoke_loader
389 }
996be9ee 390
391 return $self;
392}
393
394=head2 clone
395
530e0bf6 396See L<DBIx::Class::Schema/clone>.
996be9ee 397
398=cut
399
400sub clone {
401 my $self = shift;
402
403 my $clone = $self->next::method(@_);
404
fa994d3c 405 if($clone->_loader_args) {
406 $clone->_loader_args->{schema} = $clone;
407 weaken($clone->_loader_args->{schema});
408 }
996be9ee 409
410 $clone;
411}
412
413=head2 dump_to_dir
414
530e0bf6 415=over 4
416
417=item Argument: $directory
418
419=back
996be9ee 420
421Calling this as a class method on either L<DBIx::Class::Schema::Loader>
707fb247 422or any derived schema class will cause all schemas to dump
996be9ee 423manual versions of themselves to the named directory when they are
424loaded. In order to be effective, this must be set before defining a
425connection on this schema class or any derived object (as the loading
074e81cd 426happens as soon as both a connection and loader_options are set, and
427only once per class).
996be9ee 428
429See L<DBIx::Class::Schema::Loader::Base/dump_directory> for more
430details on the dumping mechanism.
431
432This can also be set at module import time via the import option
433C<dump_to_dir:/foo/bar> to L<DBIx::Class::Schema::Loader>, where
434C</foo/bar> is the target directory.
435
436Examples:
437
438 # My::Schema isa DBIx::Class::Schema::Loader, and has connection info
439 # hardcoded in the class itself:
440 perl -MDBIx::Class::Schema::Loader=dump_to_dir:/foo/bar -MMy::Schema -e1
441
442 # Same, but no hard-coded connection, so we must provide one:
443 perl -MDBIx::Class::Schema::Loader=dump_to_dir:/foo/bar -MMy::Schema -e 'My::Schema->connection("dbi:Pg:dbname=foo", ...)'
444
445 # Or as a class method, as long as you get it done *before* defining a
446 # connection on this schema class or any derived object:
447 use My::Schema;
448 My::Schema->dump_to_dir('/foo/bar');
449 My::Schema->connection(........);
450
451 # Or as a class method on the DBIx::Class::Schema::Loader itself, which affects all
452 # derived schemas
453 use My::Schema;
454 use My::OtherSchema;
455 DBIx::Class::Schema::Loader->dump_to_dir('/foo/bar');
456 My::Schema->connection(.......);
457 My::OtherSchema->connection(.......);
458
459 # Another alternative to the above:
460 use DBIx::Class::Schema::Loader qw| dump_to_dir:/foo/bar |;
461 use My::Schema;
462 use My::OtherSchema;
463 My::Schema->connection(.......);
464 My::OtherSchema->connection(.......);
465
466=cut
467
468sub import {
469 my $self = shift;
a8d229ff 470
996be9ee 471 return if !@_;
a8d229ff 472
473 my $cpkg = (caller)[0];
474
996be9ee 475 foreach my $opt (@_) {
476 if($opt =~ m{^dump_to_dir:(.*)$}) {
477 $self->dump_to_dir($1)
478 }
479 elsif($opt eq 'make_schema_at') {
480 no strict 'refs';
996be9ee 481 *{"${cpkg}::make_schema_at"} = \&make_schema_at;
482 }
a8d229ff 483 elsif($opt eq 'naming') {
484 no strict 'refs';
f3bed1f1 485 *{"${cpkg}::naming"} = $self->curry::naming;
a8d229ff 486 }
f22644d7 487 elsif($opt eq 'use_namespaces') {
488 no strict 'refs';
f3bed1f1 489 *{"${cpkg}::use_namespaces"} = $self->curry::use_namespaces,
f22644d7 490 }
996be9ee 491 }
492}
493
494=head2 make_schema_at
495
530e0bf6 496=over 4
497
707fb247 498=item Arguments: $schema_class_name, \%loader_options, \@connect_info
530e0bf6 499
707fb247 500=item Return Value: $schema_class_name
530e0bf6 501
502=back
503
707fb247 504This function creates a DBIx::Class schema from an existing RDBMS
505schema. With the C<dump_directory> option, generates a set of
506DBIx::Class classes from an existing database schema read from the
507given dsn. Without a C<dump_directory>, creates schema classes in
508memory at runtime without generating on-disk class files.
996be9ee 509
707fb247 510For a complete list of supported loader_options, see
511L<DBIx::Class::Schema::Loader::Base>
483987b9 512
35a87f06 513The last hashref in the C<\@connect_info> can specify the L</loader_class>.
514
707fb247 515This function can be imported in the usual way, as illustrated in
516these Examples:
996be9ee 517
5223f24a 518 # Simple example, creates as a new class 'New::Schema::Name' in
519 # memory in the running perl interpreter.
996be9ee 520 use DBIx::Class::Schema::Loader qw/ make_schema_at /;
521 make_schema_at(
522 'New::Schema::Name',
59cfa251 523 { debug => 1 },
35a87f06 524 [ 'dbi:Pg:dbname="foo"','postgres','',
525 { loader_class => 'MyLoader' } # optionally
526 ],
996be9ee 527 );
528
707fb247 529 # Inside a script, specifying a dump directory in which to write
530 # class files
996be9ee 531 use DBIx::Class::Schema::Loader qw/ make_schema_at /;
532 make_schema_at(
533 'New::Schema::Name',
59cfa251 534 { debug => 1, dump_directory => './lib' },
35a87f06 535 [ 'dbi:Pg:dbname="foo"','postgres','',
536 { loader_class => 'MyLoader' } # optionally
537 ],
996be9ee 538 );
539
b486b265 540The last hashref in the C<\@connect_info> is checked for loader arguments such
541as C<loader_options> and C<loader_class>, see L</connection> for more details.
542
996be9ee 543=cut
544
545sub make_schema_at {
546 my ($target, $opts, $connect_info) = @_;
547
483987b9 548 {
549 no strict 'refs';
550 @{$target . '::ISA'} = qw/DBIx::Class::Schema::Loader/;
551 }
552
23fd9773 553 $target->_loader_invoked(0);
71a6e88a 554
483987b9 555 $target->loader_options($opts);
23fd9773 556
557 my $temp_schema = $target->connect(@$connect_info);
558
559 $target->storage($temp_schema->storage);
560 $target->storage->set_schema($target);
561
562 return $target;
996be9ee 563}
564
b97c2c1e 565=head2 rescan
566
530e0bf6 567=over 4
568
569=item Return Value: @new_monikers
570
571=back
572
b97c2c1e 573Re-scans the database for newly added tables since the initial
574load, and adds them to the schema at runtime, including relationships,
575etc. Does not process drops or changes.
576
a60b5b8d 577Returns a list of the new monikers added.
578
b97c2c1e 579=cut
580
39d5612f 581sub rescan { my $self = shift; $self->loader->rescan($self) }
b97c2c1e 582
a8d229ff 583=head2 naming
584
585=over 4
586
587=item Arguments: \%opts | $ver
588
589=back
590
591Controls the naming options for backward compatibility, see
592L<DBIx::Class::Schema::Loader::Base/naming> for details.
593
594To upgrade a dynamic schema, use:
595
596 __PACKAGE__->naming('current');
597
598Can be imported into your dump script and called as a function as well:
599
600 naming('v4');
996be9ee 601
f22644d7 602=head2 use_namespaces
603
604=over 4
605
606=item Arguments: 1|0
607
608=back
609
610Controls the use_namespaces options for backward compatibility, see
611L<DBIx::Class::Schema::Loader::Base/use_namespaces> for details.
612
613To upgrade a dynamic schema, use:
614
615 __PACKAGE__->use_namespaces(1);
616
617Can be imported into your dump script and called as a function as well:
618
619 use_namespaces(1);
620
996be9ee 621=head1 KNOWN ISSUES
622
623=head2 Multiple Database Schemas
624
c4a69b87 625See L<DBIx::Class::Schema::Loader::Base/db_schema>.
89ecd854 626
be80bba7 627=head1 ACKNOWLEDGEMENTS
a78e3fed 628
be80bba7 629Matt S Trout, all of the #dbix-class folks, and everyone who's ever sent
630in a bug report or suggestion.
fbd83464 631
8a6b44ef 632Based on L<DBIx::Class::Loader> by Sebastian Riedel
a78e3fed 633
634Based upon the work of IKEBE Tomohiro
635
b87ab391 636=head1 AUTHORS
a78e3fed 637
b87ab391 638Caelum: Rafael Kitover <rkitover@cpan.org>
be80bba7 639
b87ab391 640Dag-Erling Smørgrav <des@des.no>
be80bba7 641
b87ab391 642Matias E. Fernandez <mfernandez@pisco.ch>
be80bba7 643
b87ab391 644SineSwiper: Brendan Byrd <byrd.b@insightcom.com>
be80bba7 645
b87ab391 646TSUNODA Kazuya <drk@drk7.jp>
59388920 647
b87ab391 648acmoore: Andrew Moore <amoore@cpan.org>
be80bba7 649
b87ab391 650alnewkirk: Al Newkirk <awncorp@cpan.org>
be80bba7 651
b87ab391 652andrewalker: André Walker <andre@andrewalker.net>
be80bba7 653
b87ab391 654angelixd: Paul C. Mantz <pcmantz@cpan.org>
1f625792 655
d1d56e5e 656arc: Aaron Crane <arc@cpan.org>
657
b87ab391 658arcanez: Justin Hunter <justin.d.hunter@gmail.com>
fdd8ff16 659
b87ab391 660ash: Ash Berlin <ash@cpan.org>
65e705c3 661
b87ab391 662blblack: Brandon Black <blblack@gmail.com>
07307014 663
b87ab391 664bphillips: Brian Phillips <bphillips@cpan.org>
7b505bbd 665
b87ab391 666btilly: Ben Tilly <btilly@gmail.com>
da21e0cf 667
b87ab391 668domm: Thomas Klausner <domm@plix.at>
c21bfb92 669
b87ab391 670gugu: Andrey Kostenko <a.kostenko@rambler-co.ru>
d36c8734 671
b87ab391 672hobbs: Andrew Rodland <arodland@cpan.org>
827dff19 673
b87ab391 674ilmari: Dagfinn Ilmari MannsE<aring>ker <ilmari@ilmari.org>
43b982ea 675
b87ab391 676jhannah: Jay Hannah <jay@jays.net>
96f68869 677
b87ab391 678jnap: John Napiorkowski <jjn1056@yahoo.com>
2a5dcfb3 679
b87ab391 680kane: Jos Boumans <kane@cpan.org>
8763ffda 681
b87ab391 682mattp: Matt Phillips <mattp@cpan.org>
c899395b 683
b87ab391 684mephinet: Philipp Gortan <philipp.gortan@apa.at>
9fd0726a 685
b87ab391 686moritz: Moritz Lenz <moritz@faui2k3.org>
c9cf9b4d 687
b87ab391 688mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
12333562 689
b87ab391 690mstratman: Mark A. Stratman <stratman@gmail.com>
71687093 691
b87ab391 692oalders: Olaf Alders <olaf@wundersolutions.com>
07f39b47 693
b87ab391 694rbo: Robert Bohne <rbo@cpan.org>
006c8ed3 695
b87ab391 696rbuels: Robert Buels <rbuels@gmail.com>
9890b10c 697
b87ab391 698ribasushi: Peter Rabbitson <ribasushi@cpan.org>
737700f7 699
b87ab391 700schwern: Michael G. Schwern <mschwern@cpan.org>
1f212b4b 701
b87ab391 702spb: Stephen Bennett <spb@exherbo.org>
4e887836 703
b87ab391 704timbunce: Tim Bunce <timb@cpan.org>
ba12c8ac 705
b87ab391 706waawaamilk: Nigel McNie <nigel@mcnie.name>
48c1a6c5 707
be80bba7 708... and lots of other folks. If we forgot you, please write the current
709maintainer or RT.
a78e3fed 710
9cc8e7e1 711=head1 COPYRIGHT & LICENSE
712
b87ab391 713Copyright (c) 2006 - 2015 by the aforementioned
714L<DBIx::Class::Schema::Loader/AUTHORS>.
a78e3fed 715
716This library is free software; you can redistribute it and/or modify it under
717the same terms as Perl itself.
718
719=head1 SEE ALSO
720
cb6407d7 721L<DBIx::Class>, L<DBIx::Class::Manual::Intro>, L<DBIx::Class::Tutorial>,
722L<DBIx::Class::Schema::Loader::Base>
a78e3fed 723
724=cut
725
7261;
71a6e88a 727# vim:et sts=4 sw=4 tw=0: