0.04002 - disable oracle.pm indexing and fix rescan return values
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / RelBuilder.pm
CommitLineData
996be9ee 1package DBIx::Class::Schema::Loader::RelBuilder;
2
3use strict;
4use warnings;
fa994d3c 5use Carp::Clan qw/^DBIx::Class/;
996be9ee 6use Lingua::EN::Inflect::Number ();
7
c39e3507 8our $VERSION = '0.04002';
32f784fc 9
996be9ee 10=head1 NAME
11
12DBIx::Class::Schema::Loader::RelBuilder - Builds relationships for DBIx::Class::Schema::Loader
13
14=head1 SYNOPSIS
15
16See L<DBIx::Class::Schema::Loader>
17
18=head1 DESCRIPTION
19
20This class builds relationships for L<DBIx::Class::Schema::Loader>. This
21is module is not (yet) for external use.
22
23=head1 METHODS
24
25=head2 new
26
e8ad6491 27Arguments: schema_class (scalar), inflect_plural, inflect_singular
996be9ee 28
29C<$schema_class> should be a schema class name, where the source
30classes have already been set up and registered. Column info, primary
31key, and unique constraints will be drawn from this schema for all
32of the existing source monikers.
33
996be9ee 34Options inflect_plural and inflect_singular are optional, and are better documented
35in L<DBIx::Class::Schema::Loader::Base>.
36
37=head2 generate_code
38
e8ad6491 39Arguments: local_moniker (scalar), fk_info (arrayref)
40
41This generates the code for the relationships of a given table.
42
43C<local_moniker> is the moniker name of the table which had the REFERENCES
44statements. The fk_info arrayref's contents should take the form:
45
46 [
47 {
48 local_columns => [ 'col2', 'col3' ],
49 remote_columns => [ 'col5', 'col7' ],
50 remote_moniker => 'AnotherTableMoniker',
51 },
52 {
53 local_columns => [ 'col1', 'col4' ],
54 remote_columns => [ 'col1', 'col2' ],
55 remote_moniker => 'YetAnotherTableMoniker',
56 },
57 # ...
58 ],
59
60This method will return the generated relationships as a hashref keyed on the
61class names. The values are arrayrefs of hashes containing method name and
62arguments, like so:
996be9ee 63
64 {
65 'Some::Source::Class' => [
b97c2c1e 66 { method => 'belongs_to', arguments => [ 'col1', 'Another::Source::Class' ],
67 { method => 'has_many', arguments => [ 'anothers', 'Yet::Another::Source::Class', 'col15' ],
996be9ee 68 ],
69 'Another::Source::Class' => [
70 # ...
71 ],
72 # ...
73 }
8f9d7ce5 74
996be9ee 75=cut
76
77sub new {
e8ad6491 78 my ( $class, $schema, $inflect_pl, $inflect_singular ) = @_;
996be9ee 79
80 my $self = {
81 schema => $schema,
996be9ee 82 inflect_plural => $inflect_pl,
83 inflect_singular => $inflect_singular,
84 };
85
86 bless $self => $class;
87
88 $self;
89}
90
91
92# pluralize a relationship name
93sub _inflect_plural {
94 my ($self, $relname) = @_;
95
96 if( ref $self->{inflect_plural} eq 'HASH' ) {
97 return $self->{inflect_plural}->{$relname}
98 if exists $self->{inflect_plural}->{$relname};
99 }
100 elsif( ref $self->{inflect_plural} eq 'CODE' ) {
101 my $inflected = $self->{inflect_plural}->($relname);
102 return $inflected if $inflected;
103 }
104
d3af7a07 105 return Lingua::EN::Inflect::Number::to_PL($relname);
996be9ee 106}
107
108# Singularize a relationship name
109sub _inflect_singular {
110 my ($self, $relname) = @_;
111
112 if( ref $self->{inflect_singular} eq 'HASH' ) {
113 return $self->{inflect_singular}->{$relname}
114 if exists $self->{inflect_singular}->{$relname};
115 }
116 elsif( ref $self->{inflect_singular} eq 'CODE' ) {
117 my $inflected = $self->{inflect_singular}->($relname);
118 return $inflected if $inflected;
119 }
120
d3af7a07 121 return Lingua::EN::Inflect::Number::to_S($relname);
996be9ee 122}
123
124sub generate_code {
e8ad6491 125 my ($self, $local_moniker, $rels) = @_;
996be9ee 126
127 my $all_code = {};
128
e8ad6491 129 my $local_table = $self->{schema}->source($local_moniker)->from;
130 my $local_class = $self->{schema}->class($local_moniker);
996be9ee 131
e8ad6491 132 my %counters;
133 foreach my $rel (@$rels) {
134 next if !$rel->{remote_source};
135 $counters{$rel->{remote_source}}++;
136 }
137
138 foreach my $rel (@$rels) {
139 next if !$rel->{remote_source};
140 my $local_cols = $rel->{local_columns};
141 my $remote_cols = $rel->{remote_columns};
142 my $remote_moniker = $rel->{remote_source};
143 my $remote_obj = $self->{schema}->source($remote_moniker);
144 my $remote_class = $self->{schema}->class($remote_moniker);
145 my $remote_table = $remote_obj->from;
146 $remote_cols ||= [ $remote_obj->primary_columns ];
147
148 if($#$local_cols != $#$remote_cols) {
149 croak "Column count mismatch: $local_moniker (@$local_cols) "
150 . "$remote_moniker (@$remote_cols)";
996be9ee 151 }
152
e8ad6491 153 my %cond;
154 foreach my $i (0 .. $#$local_cols) {
155 $cond{$remote_cols->[$i]} = $local_cols->[$i];
156 }
996be9ee 157
e8ad6491 158 my $local_relname;
e8ad6491 159 my $remote_relname;
996be9ee 160
54700b71 161 # for single-column case, set the remote relname to the column
162 # name, to make filter accessors work
e8ad6491 163 if(scalar keys %cond == 1) {
164 my ($col) = keys %cond;
165 $remote_relname = $self->_inflect_singular($cond{$col});
166 }
167 else {
168 $remote_relname = $self->_inflect_singular(lc $remote_table);
169 }
996be9ee 170
54700b71 171 # If more than one rel between this pair of tables, use the local
172 # col names to distinguish
173 if($counters{$remote_moniker} > 1) {
174 my $colnames = q{_} . join(q{_}, @$local_cols);
175 $local_relname = $self->_inflect_plural(
176 lc($local_table) . $colnames
177 );
178 $remote_relname .= $colnames if keys %cond > 1;
179 } else {
180 $local_relname = $self->_inflect_plural(lc $local_table);
181 }
996be9ee 182
e8ad6491 183 my %rev_cond = reverse %cond;
996be9ee 184
e8ad6491 185 for (keys %rev_cond) {
186 $rev_cond{"foreign.$_"} = "self.".$rev_cond{$_};
187 delete $rev_cond{$_};
188 }
996be9ee 189
e8ad6491 190 push(@{$all_code->{$local_class}},
191 { method => 'belongs_to',
192 args => [ $remote_relname,
193 $remote_class,
194 \%cond,
195 ],
996be9ee 196 }
e8ad6491 197 );
198
199 push(@{$all_code->{$remote_class}},
200 { method => 'has_many',
201 args => [ $local_relname,
202 $local_class,
203 \%rev_cond,
204 ],
205 }
206 );
996be9ee 207 }
208
209 return $all_code;
210}
211
2121;