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