line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::DBI::Loader::Relationship; |
2
|
1
|
|
|
1
|
|
746
|
use 5.006; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
32
|
|
3
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
26
|
|
4
|
1
|
|
|
1
|
|
19
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
69
|
|
5
|
|
|
|
|
|
|
our $VERSION = '1.2'; |
6
|
|
|
|
|
|
|
our $DEBUG = 0; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
1; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Class::DBI::Loader::Relationship - Easier relationship specification in CDBI::L |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Class::DBI::Loader::Relationship; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my $loader = Class::DBI::Loader->new( dsn => "mysql:beerdb", |
19
|
|
|
|
|
|
|
namespace => "BeerDB"); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Now instead of saying |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
BeerDB::Brewery->has_many(beers => "BeerDB::Beer"); |
24
|
|
|
|
|
|
|
BeerDB::Beer->has_a(brewery => "BeerDB::Brewery"); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
BeerDB::Handpump->has_a(beer => "BeerDB::Beer"); |
27
|
|
|
|
|
|
|
BeerDB::Handpump->has_a(pub => "BeerDB::Pub"); |
28
|
|
|
|
|
|
|
BeerDB::Pub->has_many(beers => [ BeerDB::Handpump => 'beer' ]); |
29
|
|
|
|
|
|
|
BeerDB::Beer->has_many(pubs => [ BeerDB::Handpump => 'pub' ]); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Just say |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
$loader->relationship( "a brewery produces beers" ); |
34
|
|
|
|
|
|
|
$loader->relationship( "a pub has beers on handpumps" ); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 DESCRIPTION |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
This module acts as a mix-in, adding the C method to |
39
|
|
|
|
|
|
|
C. Since C knows how to map |
40
|
|
|
|
|
|
|
between table names and class names, there ought to be no need to |
41
|
|
|
|
|
|
|
replicate the names. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
In addition, it is common (but not universal) to want reverse relationships |
44
|
|
|
|
|
|
|
defined for has-many relationships, and for has-a relationships to be |
45
|
|
|
|
|
|
|
defined for the linkages surrounding a many-to-many table. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The aim of C is to simplify the declaration of |
48
|
|
|
|
|
|
|
common database relationships by providing both of these features. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
The C takes a string. It recognises table names (singular |
51
|
|
|
|
|
|
|
or plural, for convenience) and extracts them from the "sentence". |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=cut |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
package Class::DBI::Loader::Generic; |
56
|
1
|
|
|
1
|
|
694
|
use Lingua::EN::Inflect::Number qw(PL to_PL to_S); |
|
1
|
|
|
|
|
567
|
|
|
1
|
|
|
|
|
6
|
|
57
|
1
|
|
|
1
|
|
279
|
use Carp; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
674
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub relationship { |
60
|
4
|
|
|
4
|
0
|
3934
|
my $self = shift; |
61
|
4
|
|
|
|
|
8
|
my $text = shift; |
62
|
4
|
|
|
|
|
20
|
my %tables = map { $_ => $_, PL($_) => $_ } $self->tables; |
|
16
|
|
|
|
|
8661
|
|
63
|
66
|
|
|
|
|
103
|
my $table_re = join "|", map quotemeta, |
64
|
4
|
|
|
|
|
818
|
sort { length $b <=> length $a } keys %tables; |
65
|
4
|
50
|
|
|
|
224
|
croak "Couldn't understand the first object you were talking about" |
66
|
|
|
|
|
|
|
unless $text =~ s/^((an?|the)\s+)?($table_re)\s*//i; |
67
|
4
|
|
|
|
|
19
|
my $from = $tables{$3}; |
68
|
4
|
|
|
|
|
25
|
my $from_c = $self->find_class($from); |
69
|
4
|
|
|
|
|
39
|
$text =~ s/^(might\s+)?\w+(\s+an?)?\s+//i; |
70
|
4
|
|
|
|
|
8
|
my $method = "has_many"; |
71
|
4
|
100
|
|
|
|
18
|
$method = "has_a" if $2; |
72
|
4
|
50
|
|
|
|
13
|
$method = "might_have" if $1; |
73
|
|
|
|
|
|
|
|
74
|
4
|
50
|
|
|
|
106
|
croak "Couldn't understand the second object you were talking about" |
75
|
|
|
|
|
|
|
unless $text =~ s/.*?($table_re)\b//i; |
76
|
4
|
|
|
|
|
10
|
my $to = $tables{$1}; |
77
|
4
|
|
|
|
|
12
|
my $to_c = $self->find_class($to); |
78
|
4
|
100
|
|
|
|
67
|
my $mapper = $method eq "has_many" ? to_PL($to) : to_S($to); |
79
|
4
|
100
|
|
|
|
4188
|
if ($text =~ /($table_re)/i) { |
80
|
1
|
|
|
|
|
4
|
my $via = $tables{$1}; my $via_c = $self->find_class($via); |
|
1
|
|
|
|
|
4
|
|
81
|
1
|
50
|
|
|
|
13
|
return "$via_c->has_a(".to_S($from)." => $from_c)\n". |
82
|
|
|
|
|
|
|
"$via_c->has_a(".to_S($to)." => $to_c)\n". |
83
|
|
|
|
|
|
|
"$from_c->$method($mapper => [ $via_c => ".to_S($to)." ])\n". |
84
|
|
|
|
|
|
|
"$to_c->has_many(".to_PL($from)." => [ $via_c => ".to_S($from)." ])\n" |
85
|
|
|
|
|
|
|
if $DEBUG; |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
0
|
$via_c->has_a(to_S($from) => $from_c); |
88
|
0
|
|
|
|
|
0
|
$via_c->has_a(to_S($to) => $to_c); |
89
|
0
|
|
|
|
|
0
|
$from_c->$method($mapper => [ $via_c => to_S($to) ]); |
90
|
0
|
|
|
|
|
0
|
$to_c->has_many(to_PL($from) => [ $via_c => to_S($from) ]); |
91
|
0
|
|
|
|
|
0
|
return; |
92
|
|
|
|
|
|
|
} |
93
|
3
|
50
|
66
|
|
|
43
|
return "$from_c->$method($mapper => $to_c);\n". |
94
|
|
|
|
|
|
|
($method ne "has_a" && "$to_c->has_a(".to_S($from)." => $from_c);\n") |
95
|
|
|
|
|
|
|
if $DEBUG; |
96
|
0
|
|
|
|
|
|
$from_c->$method($mapper => $to_c); |
97
|
0
|
0
|
|
|
|
|
$to_c->has_a(to_S($from) => $from_c) unless $method eq "has_a"; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head1 AUTHOR |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Simon Cozens, C |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head1 SEE ALSO |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
L. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=cut |