File Coverage

blib/lib/Otogiri/Plugin/TableInfo/Pg.pm
Criterion Covered Total %
statement 21 120 17.5
branch 0 24 0.0
condition 0 3 0.0
subroutine 7 21 33.3
pod 0 3 0.0
total 28 171 16.3


line stmt bran cond sub pod time code
1             package Otogiri::Plugin::TableInfo::Pg;
2 2     2   44 use 5.008005;
  2         5  
  2         63  
3 2     2   7 use strict;
  2         2  
  2         50  
4 2     2   7 use warnings;
  2         2  
  2         36  
5 2     2   8 use DBI;
  2         2  
  2         81  
6 2     2   9 use DBIx::Inspector;
  2         1  
  2         40  
7 2     2   535 use List::MoreUtils qw(any);
  2         851  
  2         172  
8 2     2   818 use Otogiri::Plugin::TableInfo::PgKeywords;
  2         2  
  2         2128  
9              
10             sub new {
11 0     0 0   my ($class, $table_info) = @_;
12 0           my $keywords = Otogiri::Plugin::TableInfo::PgKeywords->new();
13 0           my $self = {
14             table_info => $table_info,
15             keywords => $keywords,
16             };
17 0           bless $self, $class;
18             }
19              
20              
21             sub show_create_view {
22 0     0 0   my ($self, $view_name) = @_;
23 0           my ($row) = $self->{table_info}->search_by_sql('SELECT definition FROM pg_views WHERE viewname = ?', [$view_name]);
24 0           return $row->{definition};
25             }
26              
27             sub show_create_table {
28 0     0 0   my ($self, $table_name) = @_;
29 0           my $inspector = DBIx::Inspector->new(dbh => $self->{table_info}->dbh);
30 0           my $table = $inspector->table($table_name);
31              
32 0 0         return if ( !defined $table );
33              
34 0           my @indexes = $self->{table_info}->select('pg_indexes', { tablename => $table->name }, { order_by => 'indexname' });
35 0           my $result = "CREATE TABLE " . $table->name . " (\n";
36 0           $result .= $self->_build_column_defs($table);
37 0           $result .= ");\n";
38 0           $result .= $self->_build_sequence_defs($table);
39 0           $result .= $self->_build_pk_defs($table);
40 0           $result .= $self->_build_uk_defs($table, @indexes);
41 0           $result .= $self->_build_index_defs($table, @indexes);
42 0           $result .= $self->_build_fk_defs($table);
43 0           return $result;
44             }
45              
46             sub _build_column_defs {
47 0     0     my ($self, $table) = @_;
48 0           my $result = "";
49 0           for my $column ( $table->columns() ) {
50 0           my $column_name = $self->{keywords}->quote($column->name); #quote column name if it is need.
51 0           $result .= " " . $column_name . " " . $column->{PG_TYPE};
52 0 0 0       $result .= " DEFAULT " . $column->column_def if ( defined $column->column_def && !$self->_is_sequence_column($column) );
53 0 0         $result .= " NOT NULL" if ( !$column->nullable );
54 0           $result .= ",\n";
55             }
56 0           $result =~ s/,\n\z/\n/;
57 0           return $result;
58             }
59              
60             sub _build_sequence_defs {
61 0     0     my ($self, $table) = @_;
62 0           my $result = "";
63 0           my @sequence_columns = grep { $self->_is_sequence_column($_) } $table->columns();
  0            
64 0           for my $column ( @sequence_columns ) {
65 0           my $sequence_name = $self->_parse_sequence_name($column);
66 0           $result .= $self->_build_create_sequence_defs($sequence_name);
67 0           $result .= "ALTER SEQUENCE " . $sequence_name . " OWNED BY " . $table->name . "." . $column->name . ";\n";
68 0           $result .= "ALTER TABLE ONLY " . $table->name . " ALTER COLUMN " . $column->name . " SET DEFAULT " . $column->column_def . ";\n";
69             }
70 0           return $result;
71             }
72              
73             sub _parse_sequence_name {
74 0     0     my ($self, $column) = @_;
75 0 0         if ( $column->column_def =~ qr/^nextval\('([^']+)'::regclass\)/ ) {
76 0           return $1;
77             }
78 0           return;
79             }
80              
81             sub _build_create_sequence_defs {
82 0     0     my ($self, $sequence_name) = @_;
83 0           my ($row) = $self->{table_info}->select($sequence_name);
84 0           my $result = "CREATE SEQUENCE $sequence_name\n";
85 0           $result .= " START WITH " . $row->{start_value} . "\n";
86 0           $result .= " INCREMENT BY " . $row->{increment_by} . "\n";
87 0 0         if ( $row->{min_value} eq '1' ) {
88 0           $result .= " NO MINVALUE\n";
89             }
90             else {
91 0           $result .= " MINVALUE " . $row->{min_value} . "\n";
92             }
93              
94 0 0         if ( $row->{max_value} eq '9223372036854775807' ) {
95 0           $result .= " NO MAXVALUE\n";
96             }
97             else {
98 0           $result .= " MAXVALUE " . $row->{max_value} . "\n";
99             }
100              
101 0           $result .= " CACHE " . $row->{cache_value} . ";\n";
102 0           return $result;
103             }
104              
105             sub _is_sequence_column {
106 0     0     my ($self, $column) = @_;
107 0           my $default_value = $column->column_def;
108 0 0         return if ( !defined $default_value );
109 0           return $default_value =~ qr/^nextval\(/;
110             }
111              
112             sub _build_pk_defs {
113 0     0     my ($self, $table) = @_;
114 0           my $result = "";
115 0           for my $column ( $table->primary_key() ) {
116 0           $result .= "ALTER TABLE ONLY " . $table->name . "\n";
117 0           $result .= " ADD CONSTRAINT " . $column->{PG_COLUMN} . " PRIMARY KEY (" . $column->name . ");\n";
118             }
119 0           return $result;
120             }
121              
122             sub _build_index_defs {
123 0     0     my ($self, $table, @indexes) = @_;
124              
125 0           my @rows = grep { $_->{indexdef} !~ qr/\ACREATE UNIQUE INDEX/ } @indexes;
  0            
126              
127 0           my $result = '';
128 0           for my $row ( @rows ) {
129 0 0         next if ( $self->_is_pk($table, $row->{indexname}) );
130 0           $result .= $row->{indexdef} . ";\n";
131             }
132 0           return $result;
133             }
134              
135             sub _is_pk {
136 0     0     my ($self, $table, $column_name) = @_;
137 0     0     return any { $_->{PK_NAME} eq $column_name } $table->primary_key();
  0            
138             }
139              
140             sub _build_uk_defs {
141 0     0     my ($self, $table, @indexes) = @_;
142 0 0         my @unique_indexes = grep {
143 0           $_->{indexdef} =~ qr/\ACREATE UNIQUE INDEX/ && !$self->_is_pk($table, $_->{indexname})
144             } @indexes;
145 0           my $result = '';
146 0           for my $indexdef ( map{ $_->{indexdef} } @unique_indexes ) {
  0            
147 0           $result .= $indexdef . ";\n";
148             }
149 0           return $result;
150             }
151              
152             sub _build_fk_defs {
153 0     0     my ($self, $table) = @_;
154 0           my $result = '';
155             # UPDATE_RULE and DELETE_RULE are described in http://search.cpan.org/dist/DBI/DBI.pm#foreign_key_info
156 0           my %rule = (
157             0 => 'CASCADE',
158             1 => 'RESTRICT',
159             2 => 'SET NULL',
160             #3 => 'NO ACTION', # If NO ACTION, ON UPDATE/DELETE statament is not exist.
161             4 => 'SET DEFAULT',
162             );
163              
164 0           for my $fk_info ( $table->fk_foreign_keys() ) {
165 0           $result .= "ALTER TABLE ONLY " . $table->name . "\n";
166 0           $result .= " ADD CONSTRAINT " . $fk_info->fk_name . " FOREIGN KEY (" . $fk_info->fkcolumn_name . ")";
167 0           $result .= " REFERENCES " . $fk_info->pktable_name . "(" . $fk_info->pkcolumn_name . ")";
168 0 0         $result .= " ON UPDATE " . $rule{$fk_info->{UPDATE_RULE}} if ( exists $rule{$fk_info->{UPDATE_RULE}} );
169 0 0         $result .= " ON DELETE " . $rule{$fk_info->{DELETE_RULE}} if ( exists $rule{$fk_info->{DELETE_RULE}} );
170 0 0         $result .= " DEFERRABLE" if ( $fk_info->deferability ne '7' );
171 0           $result .= ";\n";
172             }
173 0           return $result;
174             }
175              
176              
177              
178             1;
179             __END__