File Coverage

blib/lib/Class/ReluctantORM/SQL/Table.pm
Criterion Covered Total %
statement 24 121 19.8
branch 0 40 0.0
condition 0 17 0.0
subroutine 8 25 32.0
pod 15 15 100.0
total 47 218 21.5


line stmt bran cond sub pod time code
1             package Class::ReluctantORM::SQL::Table;
2              
3             =head1 NAME
4              
5             Class::ReluctantORM::SQL::Table - Represent a Table in a SQL statement
6              
7             =head1 SYNOPSIS
8              
9             use Class::ReluctantORM::SQL::Aliases;
10              
11             # TODO DOCS - synopsis is way out of date
12              
13             my $table = Class::ReluctantORM::SQL::Table->new(table => $table, schema => $schema);
14             my $table = Class::ReluctantORM::SQL::Table->new($cro_class);
15              
16             # Now use $table in other Class::ReluctantORM::SQL operations
17              
18             $string = $driver->render_aliased_table($table);
19             $string = $driver->render_table_alias_definition($table);
20              
21             =head1 DESCRIPTION
22              
23             Represents a database table in a SQL statement. Inherits from Class::ReluctantORM::SQL::From::Relation .
24              
25             =cut
26              
27 1     1   6 use strict;
  1         2  
  1         34  
28 1     1   5 use warnings;
  1         2  
  1         25  
29              
30 1     1   5 use Class::ReluctantORM::Exception;
  1         2  
  1         29  
31 1     1   6 use Data::Dumper;
  1         1  
  1         51  
32              
33 1     1   11 use Class::ReluctantORM::Utilities qw(install_method check_args);
  1         3  
  1         90  
34             our $DEBUG ||= 0;
35              
36 1     1   5 use base 'Class::ReluctantORM::SQL::From::Relation';
  1         3  
  1         758  
37              
38 1     1   7 use Class::ReluctantORM::SQL::Aliases;
  1         3  
  1         138  
39              
40 1     1   7 use Class::ReluctantORM::SQL::Column;
  1         3  
  1         13  
41              
42              
43             =head1 CONSTRUCTORS
44              
45             =cut
46              
47             =head2 $table = Table->new($cro_class);
48              
49             =head2 $table = Table->new(table => 'table_name');
50              
51             =head2 $table = Table->new(table => 'table_name', schema => 'schema_name');
52              
53             Creates a new Table reference. In the first form, the
54             Table will learn its identity from the given Class::ReluctantORM class. This is the
55             preferred approach, as it allows the table to know what columns it has, etc.
56              
57             In the second and third forms, the table is identified by an explicit table name.
58              
59             =cut
60              
61             sub new {
62 0     0 1   my $class = shift;
63 0           my $self = bless {}, $class;
64 0 0         if (@_ == 1) {
65 0           my $table_class = shift;
66             #unless ($table_class->isa('Class::ReluctantORM')) {
67             # Class::ReluctantORM::Exception::Param::WrongType->croak(param => 'class', expected => 'Class::ReluctantORM');
68             #}
69 0           $self->class($table_class);
70             } else {
71 0           my %args = check_args(args => \@_, required => [qw(table)], optional => [qw(schema columns alias)]);
72 0           $self->table($args{table});
73 0           $self->schema($args{schema});
74 0           $self->alias($args{alias});
75 0 0         if ($args{columns}) {
76 0 0         unless (ref($args{columns}) eq 'ARRAY') {
77 0           Class::ReluctantORM::Exception::Param::ExpectedArrayRef->croak(param => "columns");
78             }
79             }
80 0           $self->set('manual_columns', $args{columns});
81             }
82 0           return $self;
83             }
84              
85             =head1 ACCESSORS AND MUTATORS
86              
87             =cut
88              
89             =head2 $table->alias(...);
90              
91             =head2 $table->has_column(...);
92              
93             =head2 $table->columns(...);
94              
95             =head2 $table->tables(...);
96              
97             =head2 $table->knows_any_columns(...);
98              
99             =head2 $table->knows_all_columns(...);
100              
101             =head2 $table->pretty_print(...);
102              
103             These methods are inherited from Relation.
104              
105             =cut
106              
107             =head2 @empty = $table->child_relations();
108              
109             Always returns an empty list. Required by the Relation interface.
110              
111             =cut
112              
113 0     0 1   sub child_relations { return (); }
114              
115              
116             =head2 $table->class($cro_class);
117              
118             =head2 $class = $table->class();
119              
120             Reads or sets the Class::ReluctantORM class that this Table represents.
121             If setting, the table name and scheme name will be overwritten.
122              
123             =cut
124              
125             sub class {
126 0     0 1   my $self = shift;
127 0 0         if (@_) {
128 0           my $table_class = shift;
129 0           $self->set('class', $table_class);
130 0           $self->table($table_class->table_name);
131 0           $self->schema($table_class->schema_name);
132             }
133 0           return $self->get('class');
134             }
135              
136             =head2 $bool = $table->is_leaf_relation();
137              
138             Always returns true for this class. Required by the Relation interface.
139              
140             =cut
141              
142 0     0 1   sub is_leaf_relation { return 1; }
143              
144             =head2 $bool = $rel->is_table();
145              
146             All objects of this class return true. The class add this method to its parent class, making all other subclasses of return false.
147              
148             =cut
149              
150 0     0     install_method('Class::ReluctantORM::SQL::From::Relation', 'is_table', sub { return 0; });
151 0     0 1   sub is_table { return 1; }
152              
153             =head2 $table->schema('schema_name');
154              
155             =head2 $name = $table->schema();
156              
157             Reads or sets the schema name.
158              
159             =cut
160              
161             __PACKAGE__->mk_accessors(qw(schema));
162              
163             =head2 $table->table('table_name');
164              
165             =head2 $name = $table->table();
166              
167             Reads or sets the table name.
168              
169             =cut
170              
171             __PACKAGE__->mk_accessors(qw(table));
172              
173 0     0 1   sub tables { my @result = (shift); return @result; }
  0            
174              
175             sub knows_all_columns {
176 0     0 1   my $self = shift;
177 0           return defined($self->class());
178             }
179              
180             sub knows_any_columns {
181 0     0 1   my $self = shift;
182 0   0       return $self->class() || $self->get('manual_columns');
183             }
184              
185             sub _copy_manual_columns {
186 0     0     my $table1 = shift;
187 0           my $table2 = shift;
188 0           my @manuals;
189 0           foreach my $col ($table2->columns) {
190 0           push @manuals, Column->new(table => $table1, column => $col->column);
191             }
192 0           $table1->set('manual_columns', \@manuals);
193             }
194              
195             sub columns {
196 0     0 1   my $self = shift;
197 0 0         if ($self->class) {
    0          
198 0           return map { Column->new(column => $_, table => $self) } $self->class->column_names;
  0            
199             } elsif ($self->get('manual_columns')) {
200 0           return map { Column->new(column => $_, table => $self) } @{$self->get('manual_columns')};
  0            
  0            
201             } else {
202 0           Class::ReluctantORM::Exception::Call::NotPermitted->croak("Cannot call 'columns' when neither the class of the table nor manual columns are known");
203             }
204             }
205              
206             =head2 @cols = $t->primary_key_columns()
207              
208             Returns a list of SQL Column objects that represent the columns that make up the primary key on the table. You can only call this if $t->knows_all_columns is true; otherwise, you'll get an exception.
209              
210             =cut
211              
212             sub primary_key_columns {
213 0     0 1   my $self = shift;
214 0 0         unless ($self->knows_all_columns) { Class::ReluctantORM::Exception::Call::NotPermitted->croak('Cannot call columns when knows_all_columns is false'); }
  0            
215 0           return map { Column->new(column => $_, table => $self) } $self->class->primary_key_columns;
  0            
216             }
217              
218              
219             sub has_column {
220 0     0 1   my $self = shift;
221 0           my $col_name = shift;
222 0           my %existing;
223 0 0         if ($self->class) {
    0          
224 0           %existing = map { uc($_) => 1 } $self->class->column_names();
  0            
225             } elsif ($self->get('manual_columns')) {
226 0           %existing = map { uc($_) => 1 } @{$self->get('manual_columns')};
  0            
  0            
227             } else {
228 0           Class::ReluctantORM::Exception::Call::NotPermitted->croak('Cannot call has_columns when knows_all_columns is false');
229             }
230              
231 0           return exists($existing{uc($col_name)});
232             }
233              
234             sub pretty_print {
235 0     0 1   my $self = shift;
236 0           my %args = @_;
237 0   0       my $prefix = $args{prefix} || '';
238 0           my $str = $prefix . 'TABLE ';
239 0 0         $str .= $self->class ? ('(' . $self->class . ') ') : '';
240 0 0         $str .= $self->schema ? ($self->schema . '.') : '';
241 0           $str .= $self->table;
242 0 0         $str .= $self->alias ? ( ' AS ' . $self->alias) : '';
243 0           $str .= "\n";
244 0           return $str;
245             }
246              
247             =head2 $str = $t->display_name()
248              
249             Returns a string suitable for display to the user. Used in exception messages.
250              
251             =cut
252              
253             sub display_name {
254 0     0 1   my $self = shift;
255 0           my $str = '';
256 0 0         $str .= $self->schema ? ($self->schema . '.') : '';
257 0           $str .= $self->table;
258 0 0         $str .= $self->alias ? ( ' AS ' . $self->alias) : '';
259 0           return $str;
260             }
261              
262             =head2 $bool = $table1->is_the_same_table($table2, <$check_aliases>);
263              
264             Returns true if $table1 and $table2 refer to the same schema name and table name.
265              
266             If $check_aliases is provided and true, the two Tables must be using the same table alias.
267              
268             =cut
269              
270             sub is_the_same_table {
271 0     0 1   my $table1 = shift;
272 0           my $table2 = shift;
273 0 0         unless ($table2) { return; }
  0            
274 0           my $check_aliases = shift;
275 0 0 0       my $aliases_match =
276             $check_aliases ?
277             ($table1->alias() && $table2->alias() && ($table1->alias() eq $table2->alias())) :
278             1;
279              
280             # If we know both schemae, compare them; otherwise assume they match
281 0 0 0       my $schemas_match =
282             ($table1->schema() && $table2->schema()) ?
283             ($table1->schema() eq $table2->schema()) :
284             1;
285              
286             # Must know both names and they must match, or must know neither
287 0   0       my $table_names_match =
288             ($table1->table() && $table2->table() && ($table1->table() eq $table2->table())) ||
289             (!$table1->table() && !$table2->table());
290              
291 0   0       return $aliases_match && $schemas_match && $table_names_match;
292              
293             }
294              
295             =head2 $clone = $t->clone();
296              
297             Makes a new Table object, copying over the name, alias, schema, and class of the original.
298              
299             =cut
300              
301             sub clone {
302 0     0 1   my $self = shift;
303 0           my $class = ref $self;
304              
305 0           my $other;
306 0 0         if ($self->class) {
307 0           $other = $class->new($self->class);
308             } else {
309 0           $other = $class->new(table => $self->table);
310 0 0         if ($self->schema) {
311 0           $other->schema($self->schema());
312             }
313             }
314              
315 0 0         if ($self->alias) {
316 0           $other->alias($self->alias);
317             }
318              
319 0           return $other;
320             }
321              
322              
323             =head1 AUTHOR
324              
325             Clinton Wolfe
326              
327             =cut
328              
329              
330             1;