File Coverage

blib/lib/DBomb/Meta/TableInfo.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package DBomb::Meta::TableInfo;
2              
3             =head1 NAME
4              
5             DBomb::Meta::TableInfo -
6              
7             =head1 SYNOPSIS
8              
9             =cut
10              
11 1     1   1587 use strict;
  1         3  
  1         60  
12 1     1   7 use warnings;
  1         2  
  1         78  
13             our $VERSION = '$Revision: 1.16 $';
14              
15 1     1   49 use DBomb;
  0            
  0            
16             use DBomb::Meta::OneToMany;
17             use Carp::Assert;
18             use Carp qw(carp);
19              
20             use Class::MethodMaker
21             'new_with_init' => 'new_internal',
22             'get_set' => [qw(name),
23             qw(columns), ## Tie::IxHash {name => column_info}
24             qw(select_groups), ## {group_name => +{columns=>1} }
25             qw(primary_key), ## Key object
26             qw(keys), ## [ Keys.... ]
27             qw(has_manys), ## [ HasMany,...]
28             qw(has_queries), ## [ HasQuery,...]
29             qw(has_as), ## [ HasA,...]
30             qw(class)], ## perl package
31             'boolean' => qw(is_resolved),
32             ;
33              
34              
35             ## TableInfo->factor_new($table_name,$class)
36             sub factory_new
37             {
38             my $class = ref($_[0]) ? ref(shift) : shift;
39             my $table = shift;
40              
41             return exists(DBomb->tables->{$table})
42             ? DBomb->tables->{$table}
43             : $class->new_internal($table, @_);
44             }
45              
46             ## new TableInfo($table_name,$class)
47             sub init
48             {
49             my $self = shift;
50             $self->name ( shift);
51             $self->class ( shift);
52             my %h = ();
53             tie %h, 'Tie::IxHash';
54             $self->columns ( \%h );
55             $self->select_groups ( +{ ':all' => +{}} );
56             $self->keys ( [] );
57             $self->has_queries ( [] );
58             $self->has_manys ( [] );
59             $self->has_as ( [] );
60              
61             assert(defined($self->name), 'name defined');
62             assert(defined($self->class), 'class defined');
63              
64             DBomb->tables->{$self->name} = $self;
65             }
66              
67             ## return columns
68             sub columns_list
69             {
70             my $self = shift;
71             return [ values %{$self->columns} ];
72             }
73              
74             sub resolve
75             {
76             my $self = shift;
77              
78             if ( not defined $self->class ){
79             my $name = $self->name || '';
80             die "Table '$name' could resolve the associated class. Did you call dbo_def_data_source?";
81             }
82              
83             for ( values(%{$self->columns}),
84             $self->primary_key,
85             @{$self->keys},
86             @{$self->has_manys},
87             @{$self->has_as},
88             @{$self->has_queries}){
89             $_->resolve;
90             }
91              
92             }
93              
94             sub add_column
95             {
96             my ($self, $column) = @_;
97             assert(ref $self);
98             assert(defined $column);
99             $self->columns->{$column->name} = $column;
100              
101             ## Add it to the ':all' select group
102             $self->select_groups->{':all'}->{$column->name} = $column;
103             }
104              
105             ## add_select_group($group,$column_list)
106             sub add_select_group
107             {
108             my ($self,$group,$column_list) = @_;
109              
110             assert(UNIVERSAL::isa($self,__PACKAGE__));
111             assert(UNIVERSAL::isa($column_list,'ARRAY'));
112             for (@$column_list){
113             assert(UNIVERSAL::isa($_,'DBomb::Meta::ColumnInfo'));
114             }
115              
116             $group = "group-" . scalar keys %{$self->select_groups};
117              
118             if (exists $self->select_groups->{$group}){
119             carp "select group '$group' redefined for table @{[$self->name]}"
120             }else{
121             $self->select_groups->{$group} = +{};
122             }
123              
124             for (@$column_list){
125             $self->select_groups->{$group}->{$_->name} = $_;
126             }
127             return $self->select_groups->{$group}
128             }
129              
130             ## return a OneToMany object.
131             ## self is the 'one' end of the relationship.
132             ## $foreign_table is the 'many' end.
133             ## guess_one_to_many($foreign_table)
134             sub guess_one_to_many
135             {
136             my ($self, $f_table) = @_;
137             assert(UNIVERSAL::isa($f_table,'DBomb::Meta::TableInfo'), 'guess_one_to_many requires a table info');
138              
139             my $many_pk = $f_table->primary_key;
140             my @try_keys = grep { $_ != $many_pk } @{$f_table->keys};
141             my @ok;
142              
143             ## Try every combination of keys, starting with the primary key
144             ## A match has the same column count.,
145             ## But a good match has the same column names.
146             for my $one_key ($self->primary_key, @{$self->keys}) {
147              
148             for my $many_key (@try_keys){
149             next unless $one_key->column_count == $many_key->column_count;
150             push @ok, [ $one_key, $many_key ];
151             last; ## TODO: instead of last, compare column names.
152             }
153             }
154              
155             return undef unless @ok;
156             return new DBomb::Meta::OneToMany(@{$ok[0]});
157             }
158              
159             ## find a key that matches a column list
160             ## find_key([column_name_or_info,...])
161             sub find_key
162             {
163             my ($self, $columns_list) = @_;
164             assert(UNIVERSAL::isa($self,__PACKAGE__));
165             assert(UNIVERSAL::isa($columns_list,'ARRAY'));
166             assert(@$columns_list > 0);
167              
168             KEY: for my $key (@{$self->keys}){
169             next unless $key->column_count == @$columns_list;
170              
171             my $ix=0;
172             for my $cinfo (values %{$key->columns}){
173              
174             my $col_name = ref($columns_list->[$ix]) ? $columns_list->[$ix]->name : $columns_list->[$ix];
175             next KEY unless $col_name eq $cinfo->name;
176             }
177             continue{ $ix++ }
178              
179             ## If we got here, all names matched.
180             return $key;
181             }
182              
183             undef; ## no key found
184             }
185              
186             1;
187             __END__