File Coverage

blib/lib/Rose/DB/Object/Metadata/Auto.pm
Criterion Covered Total %
statement 54 684 7.8
branch 0 386 0.0
condition 0 142 0.0
subroutine 18 56 32.1
pod 17 33 51.5
total 89 1301 6.8


line stmt bran cond sub pod time code
1             package Rose::DB::Object::Metadata::Auto;
2              
3 32     32   480 use strict;
  32         91  
  32         1142  
4 32     32   177 no warnings 'uninitialized';
  32         97  
  32         1044  
5              
6 32     32   189 use Carp();
  32         124  
  32         603  
7              
8 32     32   254 use Rose::DB::Object::Metadata::Column::Scalar;
  32         69  
  32         1026  
9 32     32   199 use Rose::DB::Object::Metadata::ForeignKey;
  32         78  
  32         902  
10              
11 32     32   199 use Rose::DB::Object::Metadata;
  32         98  
  32         4292  
12             our @ISA = qw(Rose::DB::Object::Metadata);
13              
14             our $Debug;
15              
16             *Debug = \$Rose::DB::Object::Metadata::Debug;
17              
18             our $Sort_Columns_Alphabetically = 0; # hack for test suite
19              
20             our $VERSION = '0.786';
21              
22             our $Missing_PK_OK = 0;
23              
24             use Rose::Class::MakeMethods::Generic
25             (
26 32         569 inheritable_scalar =>
27             [
28             'default_perl_indent',
29             'default_perl_braces',
30             'default_perl_unique_key_style',
31             ],
32              
33             inheritable_hash =>
34             [
35             relationship_type_ranks => { interface => 'get_set_all' },
36             relationship_type_rank => { interface => 'get_set', hash_key => 'relationship_type_ranks' },
37             delete_relationship_type_rank => { interface => 'delete', hash_key => 'relationship_type_ranks' },
38             ],
39 32     32   247 );
  32         69  
40              
41             use Rose::Object::MakeMethods::Generic
42             (
43 32         300 'scalar --get_set_init' =>
44             [
45             'column_alias_generator',
46             'foreign_key_name_generator',
47             ],
48              
49             scalar => 'auto_init_args',
50 32     32   18660 );
  32         83  
51              
52             __PACKAGE__->relationship_type_ranks
53             (
54             'one to one' => 1,
55             'many to one' => 2,
56             'one to many' => 3,
57             'many to many' => 4,
58             );
59              
60             __PACKAGE__->default_perl_indent(4);
61             __PACKAGE__->default_perl_braces('k&r');
62             __PACKAGE__->default_perl_unique_key_style('array');
63              
64             sub auto_formatted_schema
65             {
66 0     0 0   my($self, $db) = @_;
67              
68 0   0       $db ||= $self->db;
69              
70 0           my $schema = $self->select_schema($db);
71              
72 0 0         $schema = $db->default_implicit_schema unless(defined $schema);
73              
74 0 0         if(defined $schema)
75             {
76 0 0         if($db->likes_lowercase_schema_names)
    0          
77             {
78 0           $schema = lc $schema;
79             }
80             elsif($db->likes_uppercase_schema_names)
81             {
82 0           $schema = uc $schema;
83             }
84             }
85              
86 0           return $schema;
87             }
88              
89             sub auto_formatted_catalog
90             {
91 0     0 0   my($self, $db) = @_;
92              
93 0   0       $db ||= $self->db;
94              
95 0           my $catalog = $self->select_catalog($db);
96              
97 0 0         if(defined $catalog)
98             {
99 0 0         if($db->likes_lowercase_catalog_names)
    0          
100             {
101 0           $catalog = lc $catalog;
102             }
103             elsif($db->likes_uppercase_catalog_names)
104             {
105 0           $catalog = uc $catalog;
106             }
107             }
108              
109 0           return $catalog;
110             }
111              
112             sub auto_generate_columns
113             {
114 0     0 1   my($self) = shift;
115              
116 0           my($db, $class, %columns, $catalog, $schema, $table, $error);
117              
118             TRY:
119             {
120 0           local $@;
  0            
121              
122             eval
123 0           {
124 0 0         $class = $self->class or die "Missing class!";
125              
126 0           $db = $self->db;
127 0 0         my $dbh = $db->dbh or die $db->error;
128              
129 0           local $dbh->{'FetchHashKeyName'} = 'NAME';
130              
131 0           $table = $self->table;
132              
133 0 0         $table = lc $table if($db->likes_lowercase_table_names);
134              
135 0           my $table_unquoted = $db->unquote_table_name($table);
136              
137 0           my $supports_catalog = $db->supports_catalog;
138 0           $catalog = $self->auto_formatted_catalog($db);
139 0           $schema = $self->auto_formatted_schema($db);
140              
141 0           my $sth = $dbh->column_info($catalog, $schema, $table_unquoted, '%');
142              
143 0 0         unless(defined $sth)
144             {
145 32     32   31722 no warnings; # undef strings okay
  32         106  
  32         2205  
146 0           die "No column information found for catalog '", $catalog,
147             "' schema '", $schema, "' table '", $table_unquoted, "'";
148             }
149              
150 0           COLUMN: while(my $col_info = $sth->fetchrow_hashref)
151             {
152             CHECK_TABLE: # Make sure this column is from the right table
153             {
154 32     32   246 no warnings; # Allow undef coercion to empty string
  32         93  
  32         5452  
  0            
155              
156 0           $col_info->{'TABLE_NAME'} = $db->unquote_table_name($col_info->{'TABLE_NAME'});
157              
158             next COLUMN unless((!$supports_catalog || $col_info->{'TABLE_CAT'} eq $catalog) &&
159             $col_info->{'TABLE_SCHEM'} eq $schema &&
160 0 0 0       $col_info->{'TABLE_NAME'} eq $table_unquoted);
      0        
      0        
161             }
162              
163 0 0         unless(defined $col_info->{'COLUMN_NAME'})
164             {
165 0           Carp::croak "Could not extract column name from DBI column_info()";
166             }
167              
168 0           $db->refine_dbi_column_info($col_info, $self);
169              
170             $columns{$col_info->{'COLUMN_NAME'}} =
171 0           $self->auto_generate_column($col_info->{'COLUMN_NAME'}, $col_info);
172             }
173             };
174              
175 0           $error = $@;
176             }
177              
178 0 0 0       if($error || !keys %columns)
179             {
180 32     32   250 no warnings; # undef strings okay
  32         85  
  32         42308  
181 0   0       Carp::croak "Could not auto-generate columns for class $class - ",
182             ($error || "no column info found for catalog '" . $catalog .
183             "' schema '" . $schema . "' table '$table'");
184             }
185              
186 0           $self->auto_alias_columns(values %columns);
187              
188 0 0         return wantarray ? values %columns : \%columns;
189             }
190              
191             sub auto_alias_columns
192             {
193 0     0 0   my($self) = shift;
194              
195 0           foreach my $column (@_) #(@_ == 1 && ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_)
196             {
197             # Auto-alias the column if there will be any conflicts
198 0           foreach my $type ($column->auto_method_types)
199             {
200 0           my $method = $self->method_name_from_column($column, $type);
201              
202 0 0         if($self->method_name_is_reserved($method, $self->class))
203             {
204 0           $self->auto_alias_column($column);
205 0           last; # just alias the column once
206             }
207             }
208              
209             # Re-check: errors are fatal this time
210 0           foreach my $type ($column->auto_method_types)
211             {
212 0           my $method = $self->method_name_from_column($column, $type);
213              
214 0 0         if($self->method_name_is_reserved($method, $self->class))
215             {
216 0           Carp::croak "Cannot create '$type' method named '$method' for ",
217             "column '$column' - method name is reserved";
218             }
219             }
220             }
221             }
222              
223             sub auto_generate_column
224             {
225 0     0 0   my($self, $name, $col_info) = @_;
226              
227 0           my $type = $col_info->{'TYPE_NAME'};
228 0           my $meta_class = $self->original_class;
229              
230 0 0 0       my $column_class =
231             $meta_class->column_type_class($type) || $meta_class->column_type_class('scalar')
232             or Carp::croak "No column class set for column types '$type' or 'scalar'";
233              
234 0 0         unless($self->column_class_is_loaded($column_class))
235             {
236 0           $self->load_column_class($column_class);
237             }
238              
239 0           my $column = $column_class->new(name => $name, parent => $self);
240              
241 0           $column->init_with_dbi_column_info($col_info);
242              
243 0           return $column;
244             }
245              
246 0     0 0   sub init_column_alias_generator { sub { $_[1] . '_col' } }
  0     0      
247              
248             DEFAULT_FK_NAME_GEN:
249             {
250             my %Seen_FK_Name;
251              
252             sub default_foreign_key_name_generator
253             {
254 0     0 0   my($meta, $fk) = @_;
255              
256 0           my $class = $meta->class;
257 0           my $key_columns = $fk->key_columns;
258              
259 0           my $name = $fk->name;
260              
261             # No single column whose name we can steal and then
262             # mangle to make the foreign key name, so we'll derive
263             # the foreign key name from the foreign class name.
264 0 0         if(keys %$key_columns > 1)
265             {
266 0           $name = $fk->class;
267 0           $name =~ s/::/_/g;
268 0           $name =~ s/([a-z])([A-Z])/$1_$2/g;
269 0           $name = lc $name;
270             }
271             else
272             {
273 0           my($local_column, $foreign_column) = %$key_columns;
274              
275             # Try to lop off foreign column name. Example:
276             # my_foreign_object_id -> my_foreign_object
277 0 0         if($local_column =~ s/_$foreign_column$//)
278             {
279 0           $name = $local_column;
280             }
281             else
282             {
283             # Usually, the actual column name is taken by the column accessor,
284             # but if it's not, we'll use it.
285 0 0         if(!$meta->class->can($local_column))
286             {
287 0           $name = $local_column;
288             }
289             else # otherwise, append "_object"
290             {
291 0           $name = $local_column . '_object';
292             }
293             }
294             }
295              
296             # Make sure the name's not taken, appending numbers until it's unique.
297             # See, this is why you shouldn't rely on auto_init_* all the time.
298             # You end up with lame method names.
299 0 0         if($Seen_FK_Name{$class}{$name})
300             {
301 0           my $num = 2;
302 0           my $new_name = $name;
303              
304 0           while($Seen_FK_Name{$class}{$new_name})
305             {
306 0           $new_name = $name . $num++;
307             }
308              
309 0           $name = $new_name;
310             }
311              
312 0           $Seen_FK_Name{$class}{$name}++;
313              
314 0           return $name;
315             }
316             }
317              
318 0     0 0   sub init_foreign_key_name_generator { \&default_foreign_key_name_generator }
319              
320             sub auto_alias_column
321             {
322 0     0 0   my($self, $column) = @_;
323              
324 0           my $code = $self->column_alias_generator;
325 0           local $_ = $column->name;
326              
327 0           my $alias = $code->($self, $_);
328              
329 0 0         if($self->method_name_is_reserved($alias, $self->class))
330             {
331 0           Carp::croak "Called column_alias_generator() to alias column ",
332             "'$_' but the value returned is a reserved method ",
333             "name: $alias";
334             }
335              
336 0           $column->alias($alias);
337              
338 0           return;
339             }
340              
341             sub auto_retrieve_primary_key_column_names
342             {
343 0     0 1   my($self) = shift;
344              
345 0 0         unless(defined wantarray)
346             {
347 0           Carp::croak "Useless call to auto_retrieve_primary_key_column_names() in void context";
348             }
349              
350 0           my $db = $self->db;
351 0           my $catalog = $self->auto_formatted_catalog($db);
352 0           my $schema = $self->auto_formatted_schema($db);
353              
354 0           my($pk_columns, $error);
355              
356             TRY:
357             {
358 0           local $@;
  0            
359              
360             eval
361 0           {
362 0           $pk_columns =
363             $self->db->primary_key_column_names(table => $self->table,
364             catalog => $catalog,
365             schema => $schema);
366             };
367              
368 0           $error = $@;
369             }
370              
371 0 0 0       if($error || (!$Missing_PK_OK && !@$pk_columns))
      0        
372             {
373 0 0         $error = 'no primary key columns found' unless(defined $error);
374 0   0       Carp::croak "Could not auto-retrieve primary key columns for class ",
375             $self->class, " - ",
376             ($error || "no primary key info found for catalog '" . $catalog .
377             "' schema '" . $schema . "' table '" . $self->table, "'");
378             }
379              
380 0   0       $pk_columns ||= [];
381              
382 0 0         return wantarray ? @$pk_columns : $pk_columns;
383             }
384              
385             my %Warned;
386              
387             sub auto_generate_foreign_keys
388             {
389 0     0 1   my($self, %args) = @_;
390              
391 0 0         unless(defined wantarray)
392             {
393 0           Carp::croak "Useless call to auto_generate_foreign_keys() in void context";
394             }
395              
396 0           my $no_warnings = $args{'no_warnings'};
397              
398 0           my($class, @foreign_keys, $total_fks, %used_names, $error);
399              
400             TRY:
401             {
402 0           local $@;
  0            
403              
404             eval
405 0           {
406 0 0         $class = $self->class or die "Missing class!";
407              
408 0           my $db = $self->db;
409 0 0         my $dbh = $db->dbh or die $db->error;
410              
411 0           local $dbh->{'FetchHashKeyName'} = 'NAME';
412              
413 0           my $catalog = $self->auto_formatted_catalog($db);
414 0           my $schema = $self->auto_formatted_schema($db);
415              
416 0 0         my $table = $db->likes_lowercase_table_names ? lc $self->table : $self->table;
417              
418 0           my $sth = $dbh->foreign_key_info(undef, undef, undef,
419             $catalog, $schema, $table);
420              
421             # This happens when the table has no foreign keys
422 0 0         return unless(defined $sth);
423              
424 0           my(%fk, @fk_info);
425              
426 0           FK: while(my $fk_info = $sth->fetchrow_hashref)
427             {
428 0           $db->refine_dbi_foreign_key_info($fk_info, $self);
429              
430             CHECK_TABLE: # Make sure this column is from the right table
431             {
432 32     32   307 no warnings; # Allow undef coercion to empty string
  32         114  
  32         7823  
  0            
433             next FK unless($fk_info->{'FK_TABLE_CAT'} eq $catalog &&
434             $fk_info->{'FK_TABLE_SCHEM'} eq $schema &&
435 0 0 0       $fk_info->{'FK_TABLE_NAME'} eq $table);
      0        
436             }
437              
438 0           my $local_column = $fk_info->{'FK_COLUMN_NAME'};
439 0           my $foreign_column = $fk_info->{'UK_COLUMN_NAME'};
440              
441 0   0       my $fk_id = $fk_info->{'RDBO_FK_ID'} = $fk_info->{'FK_NAME'} || $fk_info->{'UK_NAME'};
442              
443 0           $fk{$fk_id}{'key_columns'}{$local_column} = $foreign_column;
444              
445 0           push(@fk_info, $fk_info);
446             }
447              
448             # This step is important! It ensures that foreign keys will be created
449             # in a deterministic order, which in turn allows the "auto-naming" of
450             # foreign keys to work in a predictable manner. This exact sort order
451             # (lowercase table name comparisons) is part of the API for foreign
452             # key auto generation.
453             @fk_info =
454 0           sort { lc $a->{'UK_TABLE_NAME'} cmp lc $b->{'UK_TABLE_NAME'} } @fk_info;
  0            
455              
456 0           my $cm = $self->convention_manager;
457              
458 0           my %seen_fk_id;
459              
460 0           FK_INFO: foreach my $fk_info (@fk_info)
461             {
462 0           my $fk_id = $fk_info->{'RDBO_FK_ID'};
463              
464 0 0         next if($seen_fk_id{$fk_id}++);
465              
466             my $foreign_class =
467             $self->class_for(catalog => $fk_info->{'UK_TABLE_CAT'},
468             schema => $fk_info->{'UK_TABLE_SCHEM'},
469 0           table => $fk_info->{'UK_TABLE_NAME'});
470              
471 0 0         unless($foreign_class) # Give convention manager a chance
472             {
473             $foreign_class =
474             $self->convention_manager->related_table_to_class(
475 0           $fk_info->{'UK_TABLE_NAME'}, $self->class);
476              
477 0 0         unless(UNIVERSAL::isa($foreign_class, 'Rose::DB::Object'))
478             {
479             # Null convention manager may return undef
480 32     32   261 no warnings 'uninitialized';
  32         76  
  32         7109  
481 0           eval "require $foreign_class";
482 0 0 0       $foreign_class = undef if($@ || !UNIVERSAL::isa($foreign_class, 'Rose::DB::Object'));
483             }
484             }
485              
486 0 0         unless($foreign_class)
487             {
488 0 0         my $key = join($;, map { defined($_) ? $_ : "\034" } $self->class,
489 0           @$fk_info{qw(UK_TABLE_CAT UK_TABLE_SCHEM UK_TABLE_NAME)});
490              
491             # Add deferred task
492             $self->add_deferred_task(
493             {
494             class => $self->class,
495             method => 'auto_init_foreign_keys',
496             args => \%args,
497              
498             code => sub
499             {
500 0     0     $self->auto_init_foreign_keys(%args);
501 0           $self->make_foreign_key_methods(%args, preserve_existing => 1);
502             },
503              
504             check => sub
505             {
506 0     0     my $fks = $self->foreign_keys;
507 0 0         return @$fks == $total_fks ? 1 : 0;
508             },
509 0           });
510              
511 0 0 0       unless($no_warnings || $Warned{$key}++ || $self->allow_auto_initialization)
      0        
512             {
513 32     32   251 no warnings; # Allow undef coercion to empty string
  32         79  
  32         27453  
514             Carp::carp
515             "No Rose::DB::Object-derived class found for catalog '",
516             $fk_info->{'UK_TABLE_CAT'}, "' schema '",
517             $fk_info->{'UK_TABLE_SCHEM'}, "' table '",
518 0           $fk_info->{'UK_TABLE_NAME'}, "'";
519             }
520              
521 0           $total_fks++;
522 0           next FK_INFO;
523             }
524              
525 0           $fk{$fk_id}{'class'} = $foreign_class;
526              
527             my $key_name =
528             $cm->auto_foreign_key_name($foreign_class, $fk_id,
529 0           $fk{$fk_id}{'key_columns'},
530             \%used_names);
531              
532 0 0         $used_names{$key_name}++ if(defined $key_name);
533              
534 0 0 0       if(defined $key_name && length $key_name)
535             {
536 0           $fk{$fk_id}{'name'} = $key_name;
537             }
538              
539 0           $total_fks++;
540             }
541              
542 0           my(%seen, %seen_name);
543              
544 0           foreach my $fk_info (@fk_info)
545             {
546 0 0         next if($seen{$fk_info->{'RDBO_FK_ID'}}++);
547 0           my $info = $fk{$fk_info->{'RDBO_FK_ID'}};
548 0           my $fk = Rose::DB::Object::Metadata::ForeignKey->new(%$info);
549              
550 0 0         next unless(defined $fk->class);
551              
552 0 0         unless(defined $fk->name)
553             {
554 0           $fk->name($self->foreign_key_name_generator->($self, $fk));
555             }
556              
557 0           push(@foreign_keys, $fk);
558             }
559             };
560              
561 0           $error = $@;
562             }
563              
564 0 0         if($error)
565             {
566 0           Carp::croak "Could not auto-generate foreign keys for class $class - $error";
567             }
568              
569 0           @foreign_keys = sort { lc $a->name cmp lc $b->name } @foreign_keys;
  0            
570              
571 0 0         return wantarray ? @foreign_keys : \@foreign_keys;
572             }
573              
574             sub auto_init_columns
575             {
576 0     0 1   my($self, %args) = @_;
577              
578 0           my $auto_columns = $self->auto_generate_columns;
579 0           my $existing_columns = $self->columns;
580              
581 0 0 0       if(!$args{'replace_existing'} && keys %$auto_columns != @$existing_columns)
    0 0        
582             {
583 0           while(my($name, $column) = each(%$auto_columns))
584             {
585 0 0         next if($self->column($name));
586 0           $self->add_column($column);
587             }
588             }
589             elsif($args{'replace_existing'} || !@$existing_columns)
590             {
591 0           $self->columns(values %$auto_columns);
592             }
593              
594 0           return;
595             }
596              
597             sub perl_columns_definition
598             {
599 0     0 1   my($self, %args) = @_;
600              
601 0           my $for_setup = $args{'for_setup'};
602 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
603 0 0         my $braces = defined $args{'braces'} ? $args{'braces'} : $self->default_perl_braces;
604              
605 0 0         unless($indent =~ /^\d+$/)
606             {
607 0 0         Carp::croak 'Invalid ', (defined $args{'indent'} ? '' : 'default '),
608             "indent size: '$braces'";
609             }
610              
611 0           $indent = ' ' x $indent;
612              
613 0 0         my $def_start = $for_setup ? 'columns => ' : "__PACKAGE__->meta->columns";
614              
615 0 0         my $ob = $for_setup ? '[' : '(';
616 0 0         my $cb = $for_setup ? ']' : ')';
617              
618 0 0         if($braces eq 'bsd')
    0          
619             {
620 0           $def_start .= "\n$ob\n";
621             }
622             elsif($braces eq 'k&r')
623             {
624 0           $def_start .= "$ob\n";
625             }
626             else
627             {
628 0 0         Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '),
629             "brace style: '$braces'";
630             }
631              
632 0           my $max_len = 0;
633 0           my $min_len = -1;
634              
635 0           foreach my $name ($self->column_names)
636             {
637 0 0         $max_len = length($name) if(length $name > $max_len);
638 0 0 0       $min_len = length($name) if(length $name < $min_len || $min_len < 0);
639             }
640              
641 0           my @col_defs;
642              
643 32     32   283 no warnings 'uninitialized'; # ordinal_position may be undef
  32         96  
  32         64809  
644 0           foreach my $column (sort __by_rank $self->columns)
645             {
646 0           push(@col_defs, $column->perl_hash_definition(inline => 1,
647             name_padding => $max_len));
648             }
649              
650 0 0         $cb = $for_setup ? '],' : ');';
651              
652 0           my $perl = $def_start . join(",\n", map { "$indent$_" } @col_defs) . ",\n$cb\n";
  0            
653              
654 0 0         if($for_setup)
655             {
656 0           for($perl)
657             {
658 0           s/^/$indent/mg;
659 0           s/\n\z//;
660 0           s/^[ \t]+$//mg;
661             }
662             }
663              
664 0           return $perl;
665             }
666              
667             sub __by_rank
668             {
669 0     0     my $pos1 = $a->ordinal_position;
670 0           my $pos2 = $b->ordinal_position;
671              
672 0 0 0       if(!$Sort_Columns_Alphabetically && defined $pos1 && defined $pos2)
      0        
673             {
674 0   0       return $pos1 <=> $pos2 || lc($a->name) cmp lc($b->name);
675             }
676              
677 0           return lc($a->name) cmp lc($b->name);
678             }
679              
680             sub perl_foreign_keys_definition
681             {
682 0     0 1   my($self, %args) = @_;
683              
684 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
685 0 0         my $braces = defined $args{'braces'} ? $args{'braces'} : $self->default_perl_braces;
686              
687 0 0         unless($indent =~ /^\d+$/)
688             {
689 0 0         Carp::croak 'Invalid ', (defined $args{'indent'} ? '' : 'default '),
690             "indent size: '$braces'";
691             }
692              
693 0           my $indent_txt = ' ' x $indent;
694              
695 0           my $for_setup = $args{'for_setup'};
696              
697 0 0         my $def = $for_setup ?
698             $indent_txt . 'foreign_keys => ' :
699             '__PACKAGE__->meta->foreign_keys';
700              
701 0 0         my $ob = $for_setup ? '[' : '(';
702 0 0         my $cb = $for_setup ? ']' : ')';
703              
704 0 0         if($braces eq 'bsd')
    0          
705             {
706 0           $def .= "\n$ob\n";
707             }
708             elsif($braces eq 'k&r')
709             {
710 0           $def .= "$ob\n";
711             }
712             else
713             {
714 0 0         Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '),
715             "brace style: '$braces'";
716             }
717              
718 0           my @fk_defs;
719              
720 0           foreach my $fk ($self->foreign_keys)
721             {
722 0           push(@fk_defs, $fk->perl_hash_definition(indent => $indent, braces => $braces));
723             }
724              
725 0 0         return '' unless(@fk_defs);
726              
727 0           foreach my $fk_def (@fk_defs)
728             {
729 0           for($fk_def)
730             {
731 0           s/^/$indent_txt/mg;
732 0           s/^[ \t]+$//mg;
733             }
734              
735 0 0         $def .= "$fk_def,\n" . ($fk_def eq $fk_defs[-1] ? '' : "\n");
736             }
737              
738 0 0         if($for_setup)
739             {
740 0           $def .= "],\n";
741              
742 0           for($def)
743             {
744 0           s/^/$indent_txt/mg;
745 0           s/\n\z//;
746 0           s/\A$indent_txt//;
747 0           s/^[ \t]+$//mg;
748             }
749              
750 0           return $def;
751             }
752             else
753             {
754 0           return $def . ");\n";
755             }
756             }
757              
758             sub perl_relationships_definition
759             {
760 0     0 1   my($self, %args) = @_;
761              
762 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
763 0 0         my $braces = defined $args{'braces'} ? $args{'braces'} : $self->default_perl_braces;
764              
765 0 0         unless($indent =~ /^\d+$/)
766             {
767 0 0         Carp::croak 'Invalid ', (defined $args{'indent'} ? '' : 'default '),
768             "indent size: '$braces'";
769             }
770              
771 0           my $indent_txt = ' ' x $indent;
772              
773 0           my $for_setup = $args{'for_setup'};
774              
775 0 0         my $def = $for_setup ?
776             $indent_txt . 'relationships => ' :
777             '__PACKAGE__->meta->relationships';
778              
779 0 0         my $ob = $for_setup ? '[' : '(';
780 0 0         my $cb = $for_setup ? ']' : ')';
781              
782 0 0         if($braces eq 'bsd')
    0          
783             {
784 0           $def .= "\n$ob\n";
785             }
786             elsif($braces eq 'k&r')
787             {
788 0           $def .= "$ob\n";
789             }
790             else
791             {
792 0 0         Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '),
793             "brace style: '$braces'";
794             }
795              
796 0           my @rel_defs;
797              
798 0           foreach my $rel ($self->relationships)
799             {
800 0 0 0       next if($rel->can('foreign_key') && $rel->foreign_key);
801 0           push(@rel_defs, $rel->perl_hash_definition(indent => $indent, braces => $braces));
802             }
803              
804 0 0         return '' unless(@rel_defs);
805              
806 0           foreach my $rel_def (@rel_defs)
807             {
808 0           for($rel_def)
809             {
810 0           s/^/$indent_txt/mg;
811 0           s/^[ \t]+$//mg;
812             }
813              
814 0 0         $def .= "$rel_def,\n" . ($rel_def eq $rel_defs[-1] ? '' : "\n");
815             }
816              
817 0 0         if($for_setup)
818             {
819 0           $def .= "],\n";
820              
821 0           for($def)
822             {
823 0           s/^/$indent_txt/mg;
824 0           s/\n\z//;
825 0           s/\A$indent_txt//;
826 0           s/^[ \t]+$//mg;
827             }
828              
829 0           return $def;
830             }
831             else
832             {
833 0           return $def . ");\n";
834             }
835             }
836              
837             sub perl_unique_keys_definition
838             {
839 0     0 1   my($self, %args) = @_;
840              
841 0 0         my $style = defined $args{'style'} ? $args{'style'} : $self->default_perl_unique_key_style;
842 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
843 0 0         my $braces = defined $args{'braces'} ? $args{'braces'} : $self->default_perl_braces;
844              
845 0 0         unless($indent =~ /^\d+$/)
846             {
847 0 0         Carp::croak 'Invalid ', (defined $args{'indent'} ? '' : 'default '),
848             "indent size: '$braces'";
849             }
850              
851 0           $indent = ' ' x $indent;
852              
853 0           my $uk_perl_method;
854              
855 0 0         if($style eq 'array')
    0          
856             {
857 0           $uk_perl_method = 'perl_array_definition';
858             }
859             elsif($style eq 'object')
860             {
861 0           $uk_perl_method = 'perl_object_definition';
862             }
863             else
864             {
865 0 0         Carp::croak 'Invalid ', (defined $args{'style'} ? '' : 'default '),
866             "unique key style: '$style'";
867             }
868              
869 0           my @uk_defs;
870              
871 0           foreach my $uk ($self->unique_keys)
872             {
873 0           push(@uk_defs, $uk->$uk_perl_method());
874             }
875              
876 0 0         return '' unless(@uk_defs);
877              
878 0           my $for_setup = $args{'for_setup'};
879              
880 0 0         my $def_start = $for_setup ?
881             $indent . 'unique_keys => ' :
882             '__PACKAGE__->meta->unique_keys';
883              
884 0 0         my $ob = $for_setup ? '[' : '(';
885 0 0         my $cb = $for_setup ? ']' : ')';
886              
887 0 0         if(@uk_defs == 1)
    0          
    0          
888             {
889 0           $def_start .= $ob;
890             }
891             elsif($braces eq 'bsd')
892             {
893 0           $def_start .= "\n$ob\n";
894             }
895             elsif($braces eq 'k&r')
896             {
897 0           $def_start .= "$ob\n";
898             }
899             else
900             {
901 0 0         Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '),
902             "brace style: '$braces'";
903             }
904              
905 0 0         if($for_setup)
906             {
907 0 0         if(@uk_defs == 1)
908             {
909 0           $def_start =~ s/^(\s*)unique_keys/$1unique_key/;
910              
911 0           for($uk_defs[0])
912             {
913 0           s/\A\[ //;
914 0           s/ \]\z//;
915             }
916              
917 0           return "$def_start $uk_defs[0] ],";
918             }
919             else
920             {
921 0           my $perl = $def_start . join(",\n", map { "$indent$_" } @uk_defs) . ",\n],";
  0            
922              
923 0           for($perl)
924             {
925 0           s/^/$indent/mg;
926 0           s/\A$indent//;
927 0           s/^[ \t]+$//mg;
928             }
929              
930 0           return $perl;
931             }
932             }
933             else
934             {
935 0 0         if(@uk_defs == 1)
936             {
937 0           return "$def_start$uk_defs[0]);\n";
938             }
939             else
940             {
941 0           return $def_start . join(",\n", map { "$indent$_" } @uk_defs) . ",\n);\n";
  0            
942             }
943             }
944             }
945              
946             sub perl_metadata_attributes
947             {
948 0     0 0   my($self, %args) = @_;
949              
950 0           my $for_setup = $args{'for_setup'};
951 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
952              
953 0 0         $indent = $for_setup ? (' ' x $indent) : '';
954              
955 0           my @attrs;
956              
957 0           foreach my $attr (qw(allow_inline_column_values))
958             {
959 32     32   341 no strict 'refs';
  32         91  
  32         20734  
960 0 0         if(my $value = $self->$attr())
961             {
962 0 0         if($for_setup)
963             {
964 0           push(@attrs, "$attr => " . $self->perl_quote_value($value) . ',');
965             }
966             else
967             {
968 0           push(@attrs, "__PACKAGE__->meta->$attr(" . $self->perl_quote_value($value) . ');');
969             }
970             }
971             }
972              
973 0 0         return @attrs ? (join("\n", map { "$indent$_" } @attrs) . ($for_setup ? '' : "\n")) : '';
  0 0          
974             }
975              
976             sub perl_quote_value
977             {
978 0     0 0   my($self, $value) = @_;
979              
980 0 0         return $value if($value =~ /^\d+$/);
981              
982 0           for($value)
983             {
984 0           s/\\/\\\\/g;
985 0           s/'/\\'/g;
986             }
987              
988 0           return qq('$value');
989             }
990             sub perl_table_definition
991             {
992 0     0 1   my($self, %args) = @_;
993              
994 0           my $for_setup = $args{'for_setup'};
995 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
996              
997 0           my $table = $self->table;
998 0           $table =~ s/'/\\'/;
999              
1000 0 0         if($args{'for_setup'})
1001             {
1002 0           $indent = ' ' x $indent;
1003 0           return qq(${indent}table => '$table',);
1004             }
1005              
1006 0           return qq(__PACKAGE__->meta->table('$table'););
1007             }
1008              
1009             sub perl_primary_key_columns_definition
1010             {
1011 0     0 1   my($self, %args) = @_;
1012              
1013 0           my @pk_cols = $self->primary_key->column_names;
1014              
1015 0 0         Carp::croak "No primary key columns found for class ", ref($self)
1016             unless(@pk_cols);
1017              
1018 0 0         if($args{'for_setup'})
1019             {
1020 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
1021 0           $indent = ' ' x $indent;
1022 0           return $indent . 'primary_key_columns => ' .
1023             $self->primary_key->perl_array_definition . ',';
1024             }
1025             else
1026             {
1027 0           return '__PACKAGE__->meta->primary_key_columns(' .
1028             $self->primary_key->perl_array_definition . ");\n";
1029             }
1030             }
1031              
1032             sub perl_class_definition
1033             {
1034 0     0 1   my($self, %args) = @_;
1035              
1036 0 0         my $indent = defined $args{'indent'} ? $args{'indent'} : $self->default_perl_indent;
1037 0 0         my $braces = defined $args{'braces'} ? $args{'braces'} : $self->default_perl_braces;
1038              
1039 0           my $class = $self->class;
1040              
1041 32     32   341 no strict 'refs';
  32         99  
  32         99900  
1042 0   0       my $isa = delete $args{'isa'} || [ ${"${class}::ISA"}[0] || 'Rose::DB::Object' ];
1043              
1044 0 0         $isa = [ $isa ] unless(ref $isa);
1045              
1046 0           my %use;
1047              
1048 0           foreach my $fk ($self->foreign_keys)
1049             {
1050 0           $use{$fk->class}++;
1051             }
1052              
1053 0           foreach my $rel ($self->relationships)
1054             {
1055 0 0         if($rel->can('map_class'))
1056             {
1057 0           $use{$rel->map_class}++;
1058             }
1059             else
1060             {
1061 0           $use{$rel->class}++;
1062             }
1063             }
1064              
1065 0           my $foreign_modules = '';
1066              
1067 0 0 0       if(%use && !$self->auto_load_related_classes)
1068             {
1069 0           $foreign_modules = "\n\n" . join("\n", map { "use $_;"} sort keys %use);
  0            
1070             }
1071              
1072 0 0 0       if(defined $args{'use_setup'} && !$args{'use_setup'})
1073             {
1074 0           return<<"EOF";
1075             package $class;
1076              
1077             use strict;
1078              
1079             use base qw(@$isa);$foreign_modules
1080              
1081 0           @{[ $self->perl_table_definition(%args) ]}
1082              
1083 0           @{[join("\n", grep { /\S/ } $self->perl_columns_definition(%args),
  0            
1084             $self->perl_primary_key_columns_definition(%args),
1085             $self->perl_unique_keys_definition(%args),
1086             $self->perl_metadata_attributes(%args),
1087             $self->perl_foreign_keys_definition(%args),
1088             $self->perl_relationships_definition(%args))]}
1089             __PACKAGE__->meta->initialize;
1090              
1091             1;
1092             EOF
1093             }
1094             else
1095             {
1096 0           my $setup_start = '__PACKAGE__->meta->setup';
1097              
1098 0 0         if($braces eq 'bsd')
    0          
1099             {
1100 0           $setup_start .= "\n(";
1101             }
1102             elsif($braces eq 'k&r')
1103             {
1104 0           $setup_start .= "(";
1105             }
1106             else
1107             {
1108 0 0         Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '),
1109             "brace style: '$braces'";
1110             }
1111              
1112 0           $args{'for_setup'} = 1;
1113 0           $indent = ' ' x $indent;
1114              
1115 0           return<<"EOF";
1116             package $class;
1117              
1118             use strict;
1119              
1120             use base qw(@$isa);$foreign_modules
1121              
1122             $setup_start
1123 0           @{[join("\n\n", grep { /\S/ } $self->perl_table_definition(%args),
  0            
1124             $self->perl_columns_definition(%args),
1125             $self->perl_primary_key_columns_definition(%args),
1126             $self->perl_unique_keys_definition(%args),
1127             $self->perl_metadata_attributes(%args),
1128             $self->perl_foreign_keys_definition(%args),
1129             $self->perl_relationships_definition(%args))]}
1130             );
1131              
1132             1;
1133             EOF
1134             }
1135             }
1136              
1137 0     0 1   sub auto_generate_unique_keys { die "Override in subclass" }
1138              
1139             sub auto_init_unique_keys
1140             {
1141 0     0 1   my($self, %args) = @_;
1142              
1143 0 0 0       return if(exists $args{'with_unique_keys'} && !$args{'with_unique_keys'});
1144              
1145 0           my $pk_cols = join("\0", $self->primary_key_columns);
1146              
1147 0 0         unless(length $pk_cols)
1148             {
1149 0           $pk_cols = join("\0", $self->auto_retrieve_primary_key_column_names);
1150             }
1151              
1152 0           my $auto_unique_keys = $self->auto_generate_unique_keys;
1153 0           my $existing_unique_keys = $self->unique_keys;
1154              
1155 0 0 0       if(!$args{'replace_existing'} && @$auto_unique_keys != @$existing_unique_keys)
    0 0        
1156             {
1157 0           KEY: foreach my $key (@$auto_unique_keys)
1158             {
1159 0           my $id = join("\0", sort map { lc } $key->column_names);
  0            
1160              
1161 0           foreach my $existing_key (@$existing_unique_keys)
1162             {
1163 0 0         next KEY if($id eq join("\0", sort map { lc } $existing_key->column_names));
  0            
1164             }
1165              
1166             # Skip primary key
1167 0 0         next KEY if($pk_cols eq join("\0", $key->column_names));
1168              
1169 0           $self->add_unique_key($key);
1170             }
1171             }
1172             elsif($args{'replace_existing'} || !@$existing_unique_keys)
1173             {
1174 0           $self->unique_keys(@$auto_unique_keys);
1175             }
1176              
1177 0           return;
1178             }
1179              
1180             sub auto_init_foreign_keys
1181             {
1182 0     0 1   my($self, %args) = @_;
1183              
1184 0 0 0       if(exists $args{'with_foreign_keys'} && !$args{'with_foreign_keys'})
1185             {
1186 0           $self->initialized_foreign_keys(1);
1187 0           return;
1188             }
1189              
1190 0           my $auto_foreign_keys = $self->auto_generate_foreign_keys(%args);
1191 0           my $existing_foreign_keys = $self->foreign_keys;
1192              
1193 0 0 0       if(!$args{'replace_existing'} && @$auto_foreign_keys != @$existing_foreign_keys)
    0 0        
1194             {
1195 0           KEY: foreach my $key (@$auto_foreign_keys)
1196             {
1197 0           my $id = __fk_key_to_id($key); # $key->id; # might not have parent yet
1198              
1199 0           foreach my $existing_key (@$existing_foreign_keys)
1200             {
1201 0 0         next KEY if($id eq __fk_key_to_id($existing_key)); # $existing_key->id
1202             }
1203              
1204 0           $self->add_foreign_key($key);
1205             }
1206             }
1207             elsif($args{'replace_existing'} || !@$existing_foreign_keys)
1208             {
1209 0           $self->foreign_keys(@$auto_foreign_keys);
1210             }
1211              
1212 0           $self->initialized_foreign_keys(1);
1213              
1214 0           return;
1215             }
1216              
1217             sub __fk_key_to_id
1218             {
1219 0     0     my($fk) = shift;
1220              
1221 0           my $key_columns = $fk->key_columns;
1222              
1223             return
1224 0           join("\0", map { join("\1", $_, $key_columns->{$_}) } sort keys %$key_columns);
  0            
1225             }
1226              
1227             sub auto_init_primary_key_columns
1228             {
1229 0     0 1   my($self) = shift;
1230              
1231 0           my $primary_key_columns = $self->auto_retrieve_primary_key_column_names;
1232              
1233 0 0 0       unless($primary_key_columns && @$primary_key_columns)
1234             {
1235 0 0         if($Missing_PK_OK)
1236             {
1237 0           $primary_key_columns = [];
1238             }
1239             else
1240             {
1241 0           Carp::croak "Could not retrieve primary key columns for class ", ref($self);
1242             }
1243             }
1244              
1245 0           $self->primary_key_columns(@$primary_key_columns);
1246              
1247 0           return;
1248             }
1249              
1250             my %Auto_Rel_Types;
1251              
1252             sub auto_init_relationships
1253             {
1254 0     0 1   my($self) = shift;
1255 0           my(%args) = @_;
1256              
1257 0           my $type_map = $self->relationship_type_classes;
1258 0           my @all_types = keys %$type_map;
1259              
1260 0           my %types;
1261              
1262 0 0         if(delete $args{'restore_types'})
1263             {
1264 0 0         if(my $types = $Auto_Rel_Types{$self->class})
1265             {
1266 0           $args{'types'} = $types;
1267             }
1268             }
1269              
1270 0 0 0       if(exists $args{'relationship_types'} ||
      0        
1271             exists $args{'types'} ||
1272             exists $args{'with_relationships'})
1273             {
1274             my $types = exists $args{'relationship_types'} ?
1275             delete $args{'relationship_types'} :
1276             exists $args{'types'} ?
1277             delete $args{'types'} :
1278             exists $args{'with_relationships'} ?
1279 0 0         delete $args{'with_relationships'} : 1;
    0          
    0          
1280              
1281 0 0         if(ref $types)
    0          
1282             {
1283 0           %types = map { $_ => 1 } @$types;
  0            
1284 0           $Auto_Rel_Types{$self->class} = $types;
1285             }
1286             elsif($types)
1287             {
1288 0           %types = map { $_ => 1 } @all_types;
  0            
1289             }
1290             else
1291             {
1292 0           $Auto_Rel_Types{$self->class} = [];
1293             }
1294             }
1295             else
1296             {
1297 0           %types = map { $_ => 1 } @all_types;
  0            
1298             }
1299              
1300 0 0         if(delete $args{'replace_existing'})
1301             {
1302 0           foreach my $rel ($self->relationships)
1303             {
1304 0 0         next unless($types{$rel->type});
1305 0           $self->delete_relationship($rel->name);
1306             }
1307             }
1308              
1309 0           foreach my $type (sort { $self->sort_relationship_types($a, $b) } keys %types)
  0            
1310             {
1311 0           my $type_name = $type;
1312              
1313 0           for($type_name)
1314             {
1315 0           s/ /_/g;
1316 0           s/\W+//g;
1317             }
1318              
1319 0           my $method = 'auto_init_' . $type_name . '_relationships';
1320              
1321 0 0         if($self->can($method))
1322             {
1323 0           $self->$method(@_);
1324             }
1325             }
1326              
1327 0           return;
1328             }
1329              
1330             sub sort_relationship_types
1331             {
1332 0     0 0   my($self, $a, $b) = @_;
1333 0           return $self->relationship_type_rank($a) <=> $self->relationship_type_rank($b);
1334             }
1335              
1336             sub auto_init_one_to_one_relationships
1337             {
1338 0     0 0   my($self, %args) = @_;
1339              
1340 0           my $class = $self->class;
1341              
1342             # For each foreign key in this class, try to make a "one to one"
1343             # relationship in the table that the foreign key points to. But
1344             # don't do so unless the keys on both sides of the relationship
1345             # are unique or primary keys.
1346 0           FK: foreach my $fk ($self->foreign_keys)
1347             {
1348 0           my $f_class = $fk->class;
1349              
1350 0 0 0       next unless($f_class && UNIVERSAL::isa($f_class, 'Rose::DB::Object'));
1351              
1352 0           my $f_meta = $f_class->meta;
1353 0           my $key_cols = $fk->key_columns;
1354              
1355             # If both sides of the column map are unique or primary keys, then
1356             # this is really a one-to-one relationship
1357 0           my $local_key = join("\0", sort keys %$key_cols);
1358 0           my $remote_key = join("\0", sort values %$key_cols);
1359              
1360 0           my($local_unique, $remote_unique);
1361              
1362 0           my $local_meta = $class->meta;
1363              
1364 0           foreach my $uk ($local_meta->primary_key, $local_meta->unique_keys)
1365             {
1366 0           my $key = join("\0", sort $uk->columns);
1367              
1368 0 0         if($key eq $local_key)
1369             {
1370 0           $local_unique = 1;
1371 0           last;
1372             }
1373             }
1374              
1375 0           foreach my $uk ($f_meta->primary_key, $f_meta->unique_keys)
1376             {
1377 0           my $key = join("\0", sort $uk->columns);
1378              
1379 0 0         if($key eq $remote_key)
1380             {
1381 0           $remote_unique = 1;
1382 0           last;
1383             }
1384             }
1385              
1386 0 0 0       unless($local_unique && $remote_unique)
1387             {
1388 0           next FK;
1389             }
1390              
1391              
1392             # This is really a one-to-one fk/relationship
1393 0           $fk->relationship_type('one to one');
1394              
1395             # Find the associated relationship and change its type
1396 0           foreach my $rel ($self->relationships)
1397             {
1398 0 0         next unless($rel->can('foreign_key'));
1399 0 0         my $rel_fk = $rel->foreign_key or next;
1400              
1401 0 0         if($rel_fk eq $fk) # string match on stringified object
1402             {
1403 0           my $new_rel =
1404             $self->_build_relationship(name => $rel->name,
1405             type => 'one to one',
1406             info =>
1407             {
1408             class => $rel->class,
1409             column_map => scalar $rel->column_map,
1410             });
1411              
1412 0           $new_rel->foreign_key($fk);
1413              
1414 0           $self->relationship($rel->name => $new_rel);
1415             }
1416             }
1417              
1418 0           my $cm = $f_meta->convention_manager;
1419              
1420             # Also don't add one to one relationships between a class
1421             # and one of its map classes
1422 0 0 0       if($cm->is_map_class($class) && !$args{'include_map_class_relationships'})
1423             {
1424 0 0         $Debug && warn "$f_class - Refusing to make one to one relationship ",
1425             "to map class to $class\n";
1426 0           next FK;
1427             }
1428              
1429 0           my $name = $cm->auto_relationship_name_one_to_one($self->table, $class);
1430              
1431 0           my $relationship =
1432             $f_meta->_build_relationship(name => $name,
1433             type => 'one to one',
1434             info =>
1435             {
1436             class => $class,
1437             column_map => { reverse %$key_cols },
1438             });
1439              
1440             # Skip if there's already a relationship with the same id
1441 0           foreach my $rel ($f_meta->relationships)
1442             {
1443 0 0         next FK if($relationship->id eq $rel->id);
1444             }
1445              
1446             # Add the one to one relationship to the foreign class
1447 0 0         unless($f_meta->relationship($name))
1448             {
1449 0 0         $Debug && warn "$f_class - Adding one to one relationship ",
1450             "'$name' to $class\n";
1451 0           $f_meta->add_relationship($relationship);
1452             }
1453              
1454             # Create the methods, preserving existing methods
1455 0           $f_meta->make_relationship_methods(name => $name, preserve_existing => 1);
1456             }
1457              
1458 0           return;
1459             }
1460              
1461       0 0   sub auto_init_many_to_one_relationships { }
1462              
1463             sub auto_init_one_to_many_relationships
1464             {
1465 0     0 0   my($self, %args) = @_;
1466              
1467 0           my $class = $self->class;
1468              
1469             # For each foreign key in this class, try to make a "one to many"
1470             # relationship in the table that the foreign key points to. But
1471             # don't do so if there's already a one to one relationship in that
1472             # class that references all of the foreign key's columns.
1473 0           FK: foreach my $fk ($self->foreign_keys)
1474             {
1475 0           my $f_class = $fk->class;
1476              
1477 0 0 0       next unless($f_class && UNIVERSAL::isa($f_class, 'Rose::DB::Object'));
1478              
1479 0           my $f_meta = $f_class->meta;
1480 0           my $key_cols = $fk->key_columns;
1481              
1482             # Check for any one to one relationships that reference the foreign
1483             # key's columns. If found, don't try to make the one to many rel.
1484 0           REL: foreach my $rel ($f_meta->relationships)
1485             {
1486 0 0         if($rel->can('map_class'))
1487             {
1488 0 0         next unless($rel->map_class eq $class);
1489             }
1490             else
1491             {
1492 0 0         next unless($rel->class eq $class);
1493             }
1494              
1495 0 0 0       if($rel->type eq 'one to one' && !$rel->foreign_key)
1496             {
1497 0           my $skip = 1;
1498              
1499 0 0         my $col_map = $rel->column_map or next REL;
1500              
1501 0           foreach my $remote_col (values %$col_map)
1502             {
1503 0 0         $skip = 0 unless($key_cols->{$remote_col});
1504             }
1505              
1506 0 0         next FK if($skip);
1507             }
1508             }
1509              
1510             # If both sides of the column map are unique or primary keys, then
1511             # this is really a one-to-one relationship
1512 0           my $local_key = join("\0", sort keys %$key_cols);
1513 0           my $remote_key = join("\0", sort values %$key_cols);
1514              
1515 0           my($local_unique, $remote_unique);
1516              
1517 0           my $local_meta = $class->meta;
1518              
1519 0           foreach my $uk ($local_meta->primary_key, $local_meta->unique_keys)
1520             {
1521 0           my $key = join("\0", sort $uk->columns);
1522              
1523 0 0         if($key eq $local_key)
1524             {
1525 0           $local_unique = 1;
1526 0           last;
1527             }
1528             }
1529              
1530 0           foreach my $uk ($f_meta->primary_key, $f_meta->unique_keys)
1531             {
1532 0           my $key = join("\0", sort $uk->columns);
1533              
1534 0 0         if($key eq $remote_key)
1535             {
1536 0           $remote_unique = 1;
1537 0           last;
1538             }
1539             }
1540              
1541 0 0 0       if($local_unique && $remote_unique)
1542             {
1543 0           next FK;
1544             }
1545              
1546 0           my $cm = $f_meta->convention_manager;
1547              
1548             # Also don't add one to many relationships between a class
1549             # and one of its map classes
1550 0 0 0       if($cm->is_map_class($class) && !$args{'include_map_class_relationships'})
1551             {
1552 0 0         $Debug && warn "$f_class - Refusing to make one to many relationship ",
1553             "to map class to $class\n";
1554 0           next FK;
1555             }
1556              
1557 0           my $name = $cm->auto_relationship_name_one_to_many($self->table, $class);
1558              
1559 0           my $relationship =
1560             $f_meta->_build_relationship(name => $name,
1561             type => 'one to many',
1562             info =>
1563             {
1564             class => $class,
1565             column_map => { reverse %$key_cols },
1566             });
1567              
1568             # Skip if there's already a relationship with the same id
1569 0           foreach my $rel ($f_meta->relationships)
1570             {
1571 0 0         next FK if($relationship->id eq $rel->id);
1572             }
1573              
1574             # Add the one to many relationship to the foreign class
1575 0 0         unless($f_meta->relationship($name))
1576             {
1577 0 0         $Debug && warn "$f_class - Adding one to many relationship ",
1578             "'$name' to $class\n";
1579 0           $f_meta->add_relationship($relationship);
1580             }
1581              
1582             # Create the methods, preserving existing methods
1583 0           $f_meta->make_relationship_methods(name => $name, preserve_existing => 1);
1584             }
1585              
1586 0           return;
1587             }
1588              
1589             sub auto_init_many_to_many_relationships
1590             {
1591 0     0 0   my($self, %args) = @_;
1592              
1593 0           my $class = $self->class;
1594              
1595 0           my $cm = $self->convention_manager;
1596              
1597             # Nevermind if this isn't a map class
1598 0 0         return unless($cm->is_map_class($class));
1599              
1600 0           my @fks = $self->foreign_keys;
1601              
1602             # It's got to have just two foreign keys
1603 0 0         return unless(@fks == 2);
1604              
1605 0           my $key_cols1 = $fks[0]->key_columns;
1606 0           my $key_cols2 = $fks[1]->key_columns;
1607              
1608             # Each foreign key must have key columns
1609 0 0 0       return unless($key_cols1 && keys %$key_cols1 &&
      0        
      0        
1610             $key_cols2 && keys %$key_cols2);
1611              
1612 0           my $map_class = $class;
1613              
1614             # Make many to many relationships in both foreign classes that go
1615             # through this map table
1616 0           PAIR: foreach my $pair ([ @fks ], [ reverse @fks ])
1617             {
1618 0           my($fk1, $fk2) = @$pair;
1619              
1620 0           my $class1 = $fk1->class;
1621 0           my $class2 = $fk2->class;
1622              
1623 0           my $meta = $class1->meta;
1624 0           my $name = $cm->auto_relationship_name_many_to_many($fk2, $map_class);
1625              
1626 0           my $relationship =
1627             $meta->_build_relationship(name => $name,
1628             type => 'many to many',
1629             info =>
1630             {
1631             map_class => $map_class,
1632             map_from => $fk1->name,
1633             map_to => $fk2->name,
1634             });
1635              
1636             # Skip if there's already a relationship with the same id
1637 0           foreach my $rel ($meta->relationships)
1638             {
1639 0 0         next PAIR if($relationship->id eq $rel->id);
1640             }
1641              
1642 0 0         unless($meta->relationship($name))
1643             {
1644 0 0         $Debug && warn "$class1 - Adding many to many relationship '$name' ",
1645             "through $map_class to $class2\n";
1646 0           $meta->add_relationship($relationship);
1647             }
1648              
1649             # Create the methods, preserving existing methods
1650 0           $meta->make_relationship_methods(name => $name, preserve_existing => 1);
1651             }
1652              
1653 0           return;
1654             }
1655              
1656             sub auto_init_metadata_attributes
1657             {
1658 0     0 0   my($self, %args) = @_;
1659              
1660 0           foreach my $column ($self->columns)
1661             {
1662 32     32   313 no warnings 'uninitialized';
  32         80  
  32         10600  
1663 0 0         if($column->default =~ /^\w+\(.*\)$/)
1664             {
1665 0           $self->allow_inline_column_values(1);
1666 0           last;
1667             }
1668             }
1669             }
1670              
1671             sub auto_initialize
1672             {
1673 0     0 1   my($self) = shift;
1674 0           my(%args) = @_;
1675              
1676 0           $self->auto_init_args({ %args });
1677              
1678 0           $self->allow_auto_initialization(1);
1679 0           $self->is_auto_initializating(1);
1680              
1681 0           $self->auto_init_columns(@_);
1682 0           $self->auto_init_primary_key_columns;
1683 0           $self->auto_init_unique_keys(@_);
1684 0           $self->auto_init_foreign_keys(@_);
1685 0           $self->auto_init_relationships(@_);
1686 0           $self->auto_init_metadata_attributes(@_);
1687              
1688 0           $self->initialize(@_);
1689              
1690             # Don't seem to need this anymore...
1691             #unless($args{'passive'})
1692             #{
1693             # for(1 .. 2) # two passes are required to catch everything
1694             # {
1695             # $self->retry_deferred_foreign_keys;
1696             # $self->retry_deferred_relationships;
1697             # $self->retry_deferred_tasks;
1698             # }
1699             #}
1700              
1701 0 0         unless($args{'stay_connected'})
1702             {
1703 0           my $meta_class = ref $self;
1704 0           $meta_class->clear_all_dbs;
1705             }
1706              
1707 0           $self->is_auto_initializating(0);
1708 0           $self->was_auto_initialized(1);
1709              
1710 0           return;
1711             }
1712              
1713             1;
1714              
1715             __END__
1716              
1717             KNOWN BUGS:
1718              
1719             MySQL:
1720              
1721             CHAR(6) column shows up as VARCHAR(6)
1722             BIT(5) column shows up as TINYINT(1) (MySQL 5.0.2 or earlier)
1723             BOOLEAN column shows up as TINYINT(1)
1724             No native support for array types in MySQL