File Coverage

blib/lib/Data/HandyGen/mysql/TableDef.pm
Criterion Covered Total %
statement 12 107 11.2
branch 0 36 0.0
condition 0 10 0.0
subroutine 4 19 21.0
pod 10 10 100.0
total 26 182 14.2


line stmt bran cond sub pod time code
1             package Data::HandyGen::mysql::TableDef;
2              
3 26     26   192 use strict;
  26         63  
  26         788  
4 26     26   142 use warnings;
  26         60  
  26         1247  
5              
6             our $VERSION = '0.0.5';
7             $VERSION = eval $VERSION;
8              
9 26     26   152 use Carp;
  26         57  
  26         1343  
10              
11 26     26   11060 use Data::HandyGen::mysql::ColumnDef;
  26         71  
  26         35427  
12              
13              
14             =head1 NAME
15              
16             Data::HandyGen::mysql::TableDef - Manages table definition in mysql
17              
18              
19             =head1 VERSION
20              
21             This documentation refers to Data::HandyGen::mysql::TableDef version 0.0.5
22              
23              
24             =head1 SYNOPSIS
25              
26             use Data::HandyGen::mysql::TableDef;
27             use DBI;
28              
29             my $dbh = DBI->connect('dbi:mysql:dbname=testdb', 'username', 'password');
30             my $table_def = Data::HandyGen::mysql::TableDef->new( dbh => $dbh, table_name => 'table1');
31              
32              
33              
34             =head1 CAUTION
35              
36             This module is not intended for use outside Data::HandyGen. Its interface may be changed in the future.
37              
38              
39             =head1 DESCRIPTION
40              
41             This module manages a table definition in one table in Mysql.
42              
43              
44             =head1 METHODS
45              
46             =head2 new(%params)
47              
48             Constructor.
49              
50             =cut
51              
52             sub new {
53 0     0 1   my ($inv, @params) = @_;
54              
55 0 0         my %params = ( ref $params[0] eq 'HASH' ) ? %{ $params[0] } : @params;
  0            
56              
57 0   0       my $class = ref $inv || $inv;
58 0           my $self = bless { %params }, $class;
59              
60 0           $self;
61             }
62              
63              
64              
65              
66             =head2 dbh($dbh)
67              
68             Setter/getter for database handle generated by DBI.
69              
70             =cut
71              
72             sub dbh {
73 0     0 1   my ($self, $dbh) = @_;
74              
75             defined $dbh
76 0 0         and $self->{dbh} = $dbh;
77              
78 0           return $self->{dbh};
79             }
80              
81              
82             # Returns dbh. Dies if $self->dbh is empty.
83             sub _get_dbh {
84 0     0     my ($self) = @_;
85              
86 0 0         my $dbh = $self->dbh()
87             or confess "dbh is empty. You should set dbh beforehand.";
88              
89 0           return $dbh;
90             }
91              
92              
93             =head2 table_name($name)
94              
95             Setter/getter for table name.
96              
97             =cut
98              
99             sub table_name {
100 0     0 1   my ($self, $name) = @_;
101              
102 0 0         if ( defined $name ) {
103             $self->{table_name}
104 0 0         and confess "table_name is already set. You cannot change it.";
105 0           $self->{table_name} = $name;
106             }
107              
108 0           return $self->{table_name};
109             }
110              
111              
112             # Returns table_name. Dies if $self->table_name is empty.
113             sub _get_table_name {
114 0     0     my ($self) = @_;
115              
116 0           my $table_name = $self->table_name();
117 0 0         defined($table_name)
118             or confess "table_name is empty. You should set table_name beforehand.";
119              
120 0           return $table_name;
121             }
122              
123              
124             =head2 colnames()
125              
126             Returns all columns in this table. If you have a table such as
127              
128             mysql> desc table1;
129             +-------------+-------------+------+-----+---------+----------------+
130             | Field | Type | Null | Key | Default | Extra |
131             +-------------+-------------+------+-----+---------+----------------+
132             | id | int(11) | NO | PRI | NULL | auto_increment |
133             | category_id | int(11) | YES | MUL | NULL | |
134             | name | varchar(20) | NO | | NULL | |
135             | price | int(11) | NO | | NULL | |
136             +-------------+-------------+------+-----+---------+----------------+
137              
138             colnames() returns an arrayref containing 'id', 'category_id', 'name' and 'price'. Order won't be guaranteed.
139              
140              
141             =cut
142              
143             sub colnames {
144 0     0 1   my ($self) = @_;
145              
146 0           my $def = $self->def();
147 0 0         return wantarray ? keys %$def : [ keys %$def ];
148             }
149              
150              
151             =head2 def()
152              
153             Returns a table definition. It is a hashref which information is originally retrieved from information_schema.columns, which contains fields such as:
154              
155             +--------------------------+---------------------+------+-----+---------+-------+
156             | Field | Type | Null | Key | Default | Extra |
157             +--------------------------+---------------------+------+-----+---------+-------+
158             | TABLE_CATALOG | varchar(512) | NO | | | |
159             | TABLE_SCHEMA | varchar(64) | NO | | | |
160             | TABLE_NAME | varchar(64) | NO | | | |
161             | COLUMN_NAME | varchar(64) | NO | | | |
162             | ORDINAL_POSITION | bigint(21) unsigned | NO | | 0 | |
163             | COLUMN_DEFAULT | longtext | YES | | NULL | |
164             | IS_NULLABLE | varchar(3) | NO | | | |
165             | DATA_TYPE | varchar(64) | NO | | | |
166             | CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES | | NULL | |
167             | CHARACTER_OCTET_LENGTH | bigint(21) unsigned | YES | | NULL | |
168             | NUMERIC_PRECISION | bigint(21) unsigned | YES | | NULL | |
169             | NUMERIC_SCALE | bigint(21) unsigned | YES | | NULL | |
170             | CHARACTER_SET_NAME | varchar(32) | YES | | NULL | |
171             | COLLATION_NAME | varchar(32) | YES | | NULL | |
172             | COLUMN_TYPE | longtext | NO | | NULL | |
173             | COLUMN_KEY | varchar(3) | NO | | | |
174             | EXTRA | varchar(27) | NO | | | |
175             | PRIVILEGES | varchar(80) | NO | | | |
176             | COLUMN_COMMENT | varchar(1024) | NO | | | |
177             +--------------------------+---------------------+------+-----+---------+-------+
178              
179             Table definition returned by def() is like the following:
180              
181             $ret = {
182             'column_1' => {
183             TABLE_CATALOG => 'def',
184             TABLE_SCHEMA => 'test',
185             ...
186             },
187             'column_2' => {
188             TABLE_CATALOG => 'def',
189             TABLE_SCHEMA => 'test',
190             ...
191             },
192             ....
193             }
194              
195             Field names in the hashref are all converted to uppercase.
196              
197              
198             =cut
199              
200             sub def {
201 0     0 1   my ($self) = @_;
202              
203 0 0         unless ( $self->{definition} ) {
204 0           $self->{definition} = $self->_get_table_definition();
205             }
206 0           return +{ %{ $self->{definition} } };
  0            
207             }
208              
209              
210             sub _fk {
211 0     0     my ($self, $column_name) = @_;
212              
213 0   0       $self->{_fk} ||= {};
214              
215 0 0         unless ( $self->{_fk}{$column_name} ) {
216 0           my $sth = $self->_get_dbh->prepare(q{
217             SELECT referenced_table_name,
218             referenced_column_name
219             FROM information_schema.key_column_usage
220             WHERE table_schema = ?
221             AND table_name = ?
222             AND column_name = ?
223             AND referenced_table_schema IS NOT NULL
224             AND referenced_table_name IS NOT NULL
225             AND referenced_column_name IS NOT NULL
226             });
227 0 0         $sth->execute( $self->_dbname, $self->table_name, $column_name )
228             or confess "Failed to retrieve foreign key info ("
229             . $self->table_name . ", $column_name)";
230              
231 0           my @res = ();
232 0           while ( my $row = $sth->fetchrow_arrayref() ) {
233 0           push @res, { table => $row->[0], column => $row->[1] };
234             }
235              
236 0           $self->{_fk}{$column_name} = [ @res ];
237             }
238              
239 0           return $self->{_fk}{$column_name};
240             }
241              
242              
243             =head2 is_pk($colname)
244              
245             Returns 1 if $colname is one of primary key columns. Otherwise returns 0.
246              
247             =cut
248              
249             sub is_pk {
250 0     0 1   my ($self, $colname) = @_;
251              
252             return
253 0 0         ( grep { $_ eq $colname } @{ $self->pk_columns() } ) ? 1 : 0;
  0            
  0            
254             }
255              
256              
257             =head2 is_fk($colname)
258              
259             If $colname is a foreign key, returns referenced table/column name like this:
260              
261             # In case only one foreign key found
262             $ret = {
263             table => 'table name',
264             column => 'column name'
265             }
266              
267             # In case multiple foreign keys found
268             $ret = [
269             { table => 'table1', column => 'column1' },
270             { table => 'table2', column => 'column2' },
271             { table => 'table3', column => 'column3' },
272             ]
273              
274             Otherwise, returns undef.
275              
276             =cut
277              
278             sub is_fk {
279 0     0 1   my ($self, $colname) = @_;
280              
281 0           my $const_key = $self->_fk($colname);
282 0 0         if ( @$const_key == 1 ) {
    0          
283 0           return { %{ $const_key->[0] } };
  0            
284             }
285             elsif ( @$const_key == 0 ) {
286 0           return undef;
287             }
288             else {
289 0           return $const_key;
290             }
291              
292             }
293              
294              
295             =head2 pk_columns()
296              
297             Returns arrayref of column names of primary keys.
298              
299              
300             =cut
301              
302             sub pk_columns {
303 0     0 1   my ($self) = @_;
304              
305 0 0         unless ( $self->{pk_columns} ) {
306              
307 0           my $sth = $self->_get_dbh->prepare(q{
308             SELECT column_name FROM information_schema.key_column_usage
309             WHERE constraint_name = 'PRIMARY'
310             AND table_schema = ?
311             AND table_name = ?
312             ORDER BY ordinal_position
313             });
314 0 0         $sth->execute( $self->_dbname, $self->table_name )
315             or confess "Failed to retrieve primary key info (" . $self->table_name . ")";
316              
317 0           my @pk = ();
318 0           while ( my $row = $sth->fetchrow_arrayref() ) {
319 0           push @pk, $row->[0];
320             }
321              
322 0           $self->{pk_columns} = [ @pk ];
323             }
324              
325 0           return [ @{ $self->{pk_columns} } ];
  0            
326             }
327              
328              
329             =head2 column_def($column_name)
330              
331             Returns column definition (ColumnDef object)
332              
333              
334             =cut
335              
336             sub column_def {
337 0     0 1   my ($self, $column_name) = @_;
338              
339 0 0         defined $column_name
340             or confess "Column name required.";
341              
342 0   0       $self->{column_def} ||= {};
343              
344 0           my $col_def = Data::HandyGen::mysql::ColumnDef->new($column_name, $self->def->{$column_name});
345 0           $self->{column_def}{$column_name} = $col_def;
346              
347 0           return $self->{column_def}{$column_name};
348             }
349              
350              
351             =head2 get_auto_increment_value()
352              
353             Returns a value which auto_increment will generate next time.
354              
355             =cut
356              
357             sub get_auto_increment_value {
358 0     0 1   my ($self) = @_;
359              
360 0           my $table = $self->table_name;
361              
362 0           my $sql = q{SELECT AUTO_INCREMENT FROM information_schema.tables WHERE table_schema = ? AND table_name = ?};
363 0           my $sth = $self->_get_dbh()->prepare($sql);
364 0           $sth->bind_param(1, $self->_dbname);
365 0           $sth->bind_param(2, $self->table_name);
366 0           $sth->execute();
367              
368 0           my $ref = $sth->fetchrow_hashref();
369 0           my $ref_uc = { map { uc($_) => $ref->{$_} } keys %$ref };
  0            
370              
371 0           return $ref_uc->{AUTO_INCREMENT};
372             }
373              
374              
375             #
376             # Returns a set of a specified table definition.
377             # Result values is a hashref like:
378             #  $res = {
379             # (colname1) => (a record in information_schema),
380             # (colname2) => (same as above),
381             # ..
382             # }
383             #
384             sub _get_table_definition {
385 0     0     my ($self) = @_;
386              
387 0           my $sql = q{SELECT * FROM information_schema.columns WHERE table_schema = ? AND table_name = ?};
388 0           my $sth = $self->_get_dbh()->prepare($sql);
389 0           $sth->bind_param(1, $self->_dbname);
390 0           $sth->bind_param(2, $self->table_name);
391 0           $sth->execute();
392 0           my $res = {};
393 0           while ( my $ref = $sth->fetchrow_hashref ) {
394              
395             # Key name may be uppercase or lowercase depending on environment.
396             # So convert all key names into uppercase.
397 0           my $ref_uc = { map { uc($_) => $ref->{$_} } keys %$ref };
  0            
398              
399 0   0       my $column_name = $ref_uc->{COLUMN_NAME} || confess "Failed to retrieve column name.";
400 0           $res->{$column_name} = $ref_uc;
401             }
402              
403 0           return $res;
404             }
405              
406              
407             sub _dbname {
408 0     0     my ($self) = @_;
409              
410 0 0         unless ( $self->{_dbname} ) {
411 0           my $res = $self->_get_dbh()->selectall_arrayref('SELECT DATABASE()');
412 0 0         $self->{_dbname} = $res->[0]->[0]
413             or confess "Failed to get dbname";
414             }
415              
416 0           return $self->{_dbname};
417             }
418              
419              
420              
421             1;
422              
423              
424              
425             __END__
426              
427              
428             =head1 AUTHOR
429              
430             Takashi Egawa
431              
432              
433             =head1 LICENCE AND COPYRIGHT
434              
435             Copyright (c)2013-2014 Takashi Egawa. All rights reserved.
436              
437             This module is free software; you can redistribute it and/or
438             modify it under the same terms as Perl itself. See L<perlartistic>.
439              
440             This program is distributed in the hope that it will be useful,
441             but WITHOUT ANY WARRANTY; without even the implied warranty of
442             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
443