File Coverage

blib/lib/Fey/Schema.pm
Criterion Covered Total %
statement 118 118 100.0
branch 27 28 96.4
condition n/a
subroutine 19 19 100.0
pod 6 6 100.0
total 170 171 99.4


line stmt bran cond sub pod time code
1             package Fey::Schema;
2              
3 26     26   146 use strict;
  26         45  
  26         1050  
4 26     26   119 use warnings;
  26         37  
  26         780  
5 26     26   131 use namespace::autoclean;
  26         38  
  26         213  
6              
7             our $VERSION = '0.42';
8              
9 26     26   2309 use Fey::Exceptions qw( param_error );
  26         42  
  26         1548  
10 26     26   123 use Fey::NamedObjectSet;
  26         36  
  26         422  
11 26     26   9089 use Fey::SQL;
  26         73  
  26         844  
12 26     26   147 use Fey::Table;
  26         43  
  26         691  
13             use Fey::Types
14 26     26   156 qw( FK HashRef NamedObjectSet Str Table TableLikeOrName TableOrName );
  26         37  
  26         109  
15 26     26   284004 use Scalar::Util qw( blessed );
  26         142  
  26         1824  
16              
17 26     26   134 use Moose 0.90;
  26         705  
  26         193  
18 26     26   137239 use MooseX::Params::Validate 0.08 qw( pos_validated_list );
  26         803  
  26         166  
19 26     26   4858 use MooseX::SemiAffordanceAccessor 0.03;
  26         471  
  26         174  
20 26     26   76870 use MooseX::StrictConstructor 0.07;
  26         1831  
  26         202  
21              
22             has 'name' => (
23             is => 'rw',
24             isa => Str,
25             required => 1,
26             );
27              
28             has '_tables' => (
29             is => 'ro',
30             isa => NamedObjectSet,
31             default => sub { return Fey::NamedObjectSet->new() },
32             handles => {
33             tables => 'objects',
34             table => 'object',
35             },
36             init_arg => undef,
37             );
38              
39             has '_fks' => (
40             is => 'ro',
41             isa => HashRef,
42             default => sub { {} },
43             init_arg => undef,
44             );
45              
46             sub add_table {
47 221     221 1 2515 my $self = shift;
48 221         1109 my ($table) = pos_validated_list( \@_, { isa => Table } );
49              
50 221         82483 my $name = $table->name();
51 221 100       1122 param_error "The schema already contains a table named $name."
52             if $self->table($name);
53              
54 220         31479 $self->_tables->add($table);
55              
56 220         6922 $table->_set_schema($self);
57              
58 220         646 return $self;
59             }
60              
61             sub remove_table {
62 3     3 1 650 my $self = shift;
63 3         15 my ($table)
64             = pos_validated_list( \@_, { isa => TableOrName } );
65              
66 3 100       64 $table = $self->table($table)
67             unless blessed $table;
68              
69 3         206 for my $fk ( $self->foreign_keys_for_table($table) ) {
70 1         4 $self->remove_foreign_key($fk);
71             }
72              
73 3         65 $self->_tables()->delete($table);
74              
75 3         89 $table->_set_schema(undef);
76              
77 3         6 return $self;
78             }
79              
80             sub add_foreign_key {
81 140     140 1 1069 my $self = shift;
82 140         552 my ($fk) = pos_validated_list( \@_, { isa => FK } );
83              
84 140         53393 my $fk_id = $fk->id();
85              
86 140         3027 my $source_table_name = $fk->source_table()->name();
87              
88 140         208 for my $col_name ( map { $_->name() } @{ $fk->source_columns() } ) {
  140         3097  
  140         3103  
89 140         3071 $self->_fks()->{$source_table_name}{$col_name}{$fk_id} = $fk;
90             }
91              
92 140         3019 my $target_table_name = $fk->target_table()->name();
93              
94 140         220 for my $col_name ( map { $_->name() } @{ $fk->target_columns() } ) {
  140         3049  
  140         3307  
95 140         3082 $self->_fks()->{$target_table_name}{$col_name}{$fk_id} = $fk;
96             }
97              
98 140         468 return $self;
99             }
100              
101             sub remove_foreign_key {
102 4     4 1 2423 my $self = shift;
103 4         24 my ($fk) = pos_validated_list( \@_, { isa => FK } );
104              
105 4         1767 my $fk_id = $fk->id();
106              
107 4         104 my $source_table_name = $fk->source_table()->name();
108 4         7 for my $col_name ( map { $_->name() } @{ $fk->source_columns() } ) {
  4         105  
  4         104  
109 4         88 delete $self->_fks()->{$source_table_name}{$col_name}{$fk_id};
110             }
111              
112 4         83 my $target_table_name = $fk->target_table()->name();
113 4         10 for my $col_name ( map { $_->name() } @{ $fk->target_columns() } ) {
  4         117  
  4         86  
114 4         82 delete $self->_fks()->{$target_table_name}{$col_name}{$fk_id};
115             }
116              
117 4         36 return $self;
118             }
119              
120             sub foreign_keys_for_table {
121 12     12 1 615 my $self = shift;
122 12         46 my ($table)
123             = pos_validated_list( \@_, { isa => TableOrName } );
124              
125 12 100       388 my $name = blessed $table ? $table->name() : $table;
126              
127 8         171 my %fks = (
128 11         232 map { $_->id() => $_ }
129 11 100       11 map { values %{ $self->_fks()->{$name}{$_} } }
  12         295  
130 12         22 keys %{ $self->_fks()->{$name} || {} }
131             );
132              
133 12         52 return values %fks;
134             }
135              
136             sub foreign_keys_between_tables {
137 43     43 1 1221 my $self = shift;
138 43         253 my ( $table1, $table2 ) = pos_validated_list(
139             \@_,
140             { isa => TableLikeOrName },
141             { isa => TableLikeOrName }
142             );
143              
144 43 100       3061 my $name1
    100          
145             = !blessed $table1 ? $table1
146             : $table1->isa('Fey::Table') ? $table1->name()
147             : $table1->table()->name();
148              
149 43 100       984 my $name2
    100          
150             = !blessed $table2 ? $table2
151             : $table2->isa('Fey::Table') ? $table2->name()
152             : $table2->table()->name();
153              
154 40         827 my %fks = (
155 73         252 map { $_->id() => $_ }
156 49         1026 grep { $_->has_tables( $name1, $name2 ) }
157 49 100       66 map { values %{ $self->_fks()->{$name1}{$_} } }
  43         953  
158 43         72 keys %{ $self->_fks()->{$name1} || {} }
159             );
160              
161 86 100       419 return values %fks
162 43 100       90 unless grep { blessed $_ && $_->is_alias() } $table1, $table2;
163              
164 5 50       21 $table1 = $self->table($name1)
165             unless blessed $table1;
166              
167 5 100       31 $table2 = $self->table($name2)
168             unless blessed $table2;
169              
170 5         116 my @fks;
171              
172 5         18 for my $fk ( values %fks ) {
173 1         24 my %p
174             = $table1->name() eq $fk->source_table()->name()
175             ? (
176             source_columns => [
177             $table1->columns(
178 1         22 map { $_->name() } @{ $fk->source_columns() }
  1         50  
179             )
180             ],
181             target_columns => [
182             $table2->columns(
183 1         33 map { $_->name() } @{ $fk->target_columns() }
  4         117  
184             )
185             ],
186             )
187             : (
188             source_columns => [
189             $table2->columns(
190 4         143 map { $_->name() } @{ $fk->source_columns() }
  4         112  
191             )
192             ],
193             target_columns => [
194             $table1->columns(
195 5 100       59 map { $_->name() } @{ $fk->target_columns() }
  4         144  
196             )
197             ],
198             );
199              
200 5         162 push @fks, Fey::FK->new(%p);
201             }
202              
203 5         35 return @fks;
204             }
205              
206             __PACKAGE__->meta()->make_immutable();
207              
208             1;
209              
210             # ABSTRACT: Represents a schema and contains tables and foreign keys
211              
212             __END__
213              
214             =pod
215              
216             =head1 NAME
217              
218             Fey::Schema - Represents a schema and contains tables and foreign keys
219              
220             =head1 VERSION
221              
222             version 0.42
223              
224             =head1 SYNOPSIS
225              
226             my $schema = Fey::Schema->new( name => 'MySchema' );
227              
228             $schema->add_table(...);
229              
230             $schema->add_foreign_key(...);
231              
232             =head1 DESCRIPTION
233              
234             This class represents a schema, which is a set of tables and foreign
235             keys.
236              
237             =head1 METHODS
238              
239             This class provides the following methods:
240              
241             =head2 Fey::Schema->new()
242              
243             my $schema = Fey::Schema->new( name => 'MySchema' );
244              
245             This method constructs a new C<Fey::Schema> object. It takes the
246             following parameters:
247              
248             =over 4
249              
250             =item * name - required
251              
252             The name of the schema.
253              
254             =back
255              
256             =head2 $schema->name()
257              
258             Returns the name of the schema.
259              
260             =head2 $schema->add_table($table)
261              
262             Adds the specified table to the schema. The table must be a
263             C<Fey::Table> object. Adding the table to the schema sets the schema
264             for the table, so that C<< $table->schema() >> returns the correct
265             object.
266              
267             If the table is already part of the schema, an exception will be
268             thrown.
269              
270             =head2 $schema->remove_table($table)
271              
272             Remove the specified table from the schema. Removing the table also
273             removes any foreign keys which reference the table. Removing the table
274             unsets the schema for the table.
275              
276             The table can be specified either by name or by passing in a
277             C<Fey::Table> object.
278              
279             =head2 $schema->table($name)
280              
281             Returns the table with the specified name. If no such table exists,
282             this method returns false.
283              
284             =head2 $schema->tables()
285              
286             =head2 $schema->tables(@names)
287              
288             When this method is called with no arguments, it returns all of the tables in
289             the schema. Tables are returned in the order with which they were added to the
290             schema.
291              
292             If given a list of names, it returns only the specified tables. If a name is
293             given which doesn't match a table in the schema, then it is ignored.
294              
295             =head2 $schema->add_foreign_key($fk)
296              
297             Adds the specified to the schema. The foreign key must be a C<Fey::FK>
298             object.
299              
300             If the foreign key references tables which are not in the schema, an
301             exception will be thrown.
302              
303             =head2 $schema->remove_foreign_key($fk)
304              
305             Removes the specified foreign key from the schema. The foreign key
306             must be a C<Fey::FK> object.
307              
308             =head2 $schema->foreign_keys_for_table($table)
309              
310             Returns all the foreign keys which reference the specified table. The
311             table can be specified as a name or a C<Fey::Table> object.
312              
313             =head2 $schema->foreign_keys_between_tables( $source_table, $target_table )
314              
315             Returns all the foreign keys which reference both tables. The tables
316             can be specified as names, C<Fey::Table> objects, or
317             C<Fey::Table::Alias> objects. If you provide any aliases, the foreign
318             keys returned will contain columns from those aliases, not the real
319             tables. This provides support for joining an alias in a SQL statement.
320              
321             =head1 BUGS
322              
323             See L<Fey> for details on how to report bugs.
324              
325             =head1 AUTHOR
326              
327             Dave Rolsky <autarch@urth.org>
328              
329             =head1 COPYRIGHT AND LICENSE
330              
331             This software is Copyright (c) 2011 - 2015 by Dave Rolsky.
332              
333             This is free software, licensed under:
334              
335             The Artistic License 2.0 (GPL Compatible)
336              
337             =cut