line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Rose::DBx::Object::Builder; |
2
|
1
|
|
|
1
|
|
41272
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
45
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
4
|
1
|
|
|
1
|
|
6
|
no warnings 'recursion'; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
50
|
|
5
|
1
|
|
|
1
|
|
6
|
use Exporter 'import'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
43
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
12
|
use base qw(Rose::Object); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1074
|
|
8
|
|
|
|
|
|
|
our @EXPORT = qw(config parse build show); |
9
|
|
|
|
|
|
|
our @EXPORT_OK = qw(config parse build show); |
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
1774
|
use Lingua::EN::Inflect 'PL'; |
|
1
|
|
|
|
|
24587
|
|
|
1
|
|
|
|
|
144
|
|
12
|
1
|
|
|
1
|
|
1023
|
use Regexp::Common; |
|
1
|
|
|
|
|
5543
|
|
|
1
|
|
|
|
|
6
|
|
13
|
1
|
|
|
1
|
|
85533
|
use DBI; |
|
1
|
|
|
|
|
18963
|
|
|
1
|
|
|
|
|
6745
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = 0.09; |
16
|
|
|
|
|
|
|
# 12.9 |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub config { |
19
|
7
|
|
|
7
|
1
|
880
|
my $self = shift; |
20
|
7
|
100
|
66
|
|
|
52
|
unless ($self && defined $self->{CONFIG}) { |
21
|
|
|
|
|
|
|
$self->{CONFIG} = { |
22
|
|
|
|
|
|
|
db => { |
23
|
|
|
|
|
|
|
name => undef, |
24
|
|
|
|
|
|
|
type => 'mysql', |
25
|
|
|
|
|
|
|
host => '127.0.0.1', |
26
|
|
|
|
|
|
|
port => undef, |
27
|
|
|
|
|
|
|
username => 'root', |
28
|
|
|
|
|
|
|
password => 'root', |
29
|
|
|
|
|
|
|
tables_are_singular => undef, |
30
|
|
|
|
|
|
|
table_prefix => '', |
31
|
|
|
|
|
|
|
options => {RaiseError => 0, PrintError => 0, AutoCommit => 1}}, |
32
|
|
|
|
|
|
|
format => { |
33
|
|
|
|
|
|
|
expression => sub { |
34
|
35
|
|
|
35
|
|
73
|
my $expression = lc(shift); |
35
|
35
|
|
|
|
|
303
|
$expression =~ s/\s*,?\s*\band\b\s*,?\s*/, /g; |
36
|
35
|
|
|
|
|
199
|
$expression =~ s/\b(a|an|the)\b//g; |
37
|
35
|
|
|
|
|
57
|
$expression =~ s/\.//g; |
38
|
35
|
|
|
|
|
82
|
return $expression; |
39
|
|
|
|
|
|
|
}, |
40
|
|
|
|
|
|
|
table => sub { |
41
|
60
|
|
|
60
|
|
88
|
my $table = shift; |
42
|
60
|
|
|
|
|
292
|
$table =~ s/^\s+|\s+$//g; |
43
|
60
|
|
|
|
|
108
|
$table =~ s/\s+/_/g; |
44
|
60
|
|
|
|
|
189
|
return $table; |
45
|
|
|
|
|
|
|
}, |
46
|
|
|
|
|
|
|
column => sub { |
47
|
115
|
|
|
115
|
|
163
|
my $column = shift; |
48
|
115
|
|
|
|
|
510
|
$column =~ s/^\s+|\s+$//g; |
49
|
115
|
|
|
|
|
273
|
$column =~ s/\s+/_/g; |
50
|
115
|
|
|
|
|
262
|
return $column; |
51
|
|
|
|
|
|
|
}, |
52
|
|
|
|
|
|
|
}, |
53
|
1
|
|
|
|
|
65
|
table => { |
54
|
|
|
|
|
|
|
mysql => 'CREATE TABLE [% table_name %] ([% columns %]) TYPE=INNODB;', |
55
|
|
|
|
|
|
|
Pg => 'CREATE TABLE [% table_name %] ([% columns %]);', |
56
|
|
|
|
|
|
|
SQLite => 'CREATE TABLE [% table_name %] ([% columns %]);', |
57
|
|
|
|
|
|
|
}, |
58
|
|
|
|
|
|
|
primary_key => { |
59
|
|
|
|
|
|
|
name => 'id', |
60
|
|
|
|
|
|
|
type => { |
61
|
|
|
|
|
|
|
mysql => 'INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY', |
62
|
|
|
|
|
|
|
Pg => 'SERIAL PRIMARY KEY', |
63
|
|
|
|
|
|
|
SQLite => 'INTEGER NOT NULL PRIMARY KEY', |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
}, |
66
|
|
|
|
|
|
|
foreign_key => { |
67
|
|
|
|
|
|
|
suffix => '_id', |
68
|
|
|
|
|
|
|
type => { |
69
|
|
|
|
|
|
|
mysql => 'INTEGER', |
70
|
|
|
|
|
|
|
Pg => 'INTEGER', |
71
|
|
|
|
|
|
|
SQLite => 'INTEGER', |
72
|
|
|
|
|
|
|
}, |
73
|
|
|
|
|
|
|
singular => 1, |
74
|
|
|
|
|
|
|
clause => 'FOREIGN KEY ([% foreign_key %]) REFERENCES [% reference_table %] ([% reference_primary_key %]) ON UPDATE CASCADE ON DELETE CASCADE', |
75
|
|
|
|
|
|
|
}, |
76
|
|
|
|
|
|
|
add_clause => 'ALTER TABLE [% table_name %] ADD [% clause %];', |
77
|
|
|
|
|
|
|
map_table => '[% table_name %]_[% foreign_table_name %]_map', |
78
|
|
|
|
|
|
|
columns => { |
79
|
|
|
|
|
|
|
name => 'VARCHAR(255)', |
80
|
|
|
|
|
|
|
unique => 'VARCHAR(255) UNIQUE', |
81
|
|
|
|
|
|
|
required => 'VARCHAR(255) NOT NULL', |
82
|
|
|
|
|
|
|
text => 'TEXT', |
83
|
|
|
|
|
|
|
integer => 'INTEGER', |
84
|
|
|
|
|
|
|
number => 'NUMERIC', |
85
|
|
|
|
|
|
|
date => 'DATE', |
86
|
|
|
|
|
|
|
time => 'TIME', |
87
|
|
|
|
|
|
|
timestamp => 'TIMESTAMP', |
88
|
|
|
|
|
|
|
money => 'DECIMAL(13,2)', |
89
|
|
|
|
|
|
|
boolean => 'BOOLEAN', |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
}; |
92
|
|
|
|
|
|
|
|
93
|
1
|
|
|
|
|
5
|
$self->{CONFIG}->{columns}->{title} = $self->{CONFIG}->{columns}->{name}; |
94
|
1
|
|
|
|
|
5
|
$self->{CONFIG}->{columns}->{description} = $self->{CONFIG}->{columns}->{text}; |
95
|
1
|
|
|
|
|
3
|
$self->{CONFIG}->{columns}->{percentage} = $self->{CONFIG}->{columns}->{number}; |
96
|
1
|
|
|
|
|
4
|
$self->{CONFIG}->{columns}->{cost} = $self->{CONFIG}->{columns}->{money}; |
97
|
1
|
|
|
|
|
5
|
$self->{CONFIG}->{columns}->{price} = $self->{CONFIG}->{columns}->{money}; |
98
|
1
|
|
|
|
|
4
|
$self->{CONFIG}->{columns}->{username} = $self->{CONFIG}->{columns}->{unique}; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
7
|
100
|
|
|
|
22
|
if (@_) { |
102
|
1
|
|
|
|
|
2
|
my $config = shift; |
103
|
1
|
|
|
|
|
2
|
foreach my $hash (keys %{$config}) { |
|
1
|
|
|
|
|
4
|
|
104
|
1
|
50
|
|
|
|
5
|
if (ref $config->{$hash} eq 'HASH') { |
105
|
1
|
|
|
|
|
1
|
foreach my $key (keys %{$config->{$hash}}) { |
|
1
|
|
|
|
|
4
|
|
106
|
1
|
50
|
|
|
|
5
|
if (ref $config->{$hash}->{$key} eq 'HASH') { |
107
|
0
|
|
|
|
|
0
|
foreach my $sub_key (keys %{$config->{$hash}->{$key}}) { |
|
0
|
|
|
|
|
0
|
|
108
|
0
|
|
|
|
|
0
|
$self->{CONFIG}->{$hash}->{$key}->{$sub_key} = $config->{$hash}->{$key}->{$sub_key}; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
else { |
112
|
1
|
|
|
|
|
7
|
$self->{CONFIG}->{$hash}->{$key} = $config->{$hash}->{$key}; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
else { |
117
|
0
|
|
|
|
|
0
|
$self->{CONFIG}->{$hash} = $config->{$hash}; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
7
|
|
|
|
|
21
|
return $self->{CONFIG}; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub build { |
126
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
127
|
0
|
|
|
|
|
0
|
my $dbh = shift; |
128
|
0
|
|
|
|
|
0
|
my $config = $self->config; |
129
|
0
|
|
|
|
|
0
|
my $schema = $self->parse; |
130
|
0
|
0
|
|
|
|
0
|
return unless $schema; |
131
|
|
|
|
|
|
|
|
132
|
0
|
0
|
|
|
|
0
|
unless ($dbh) { |
133
|
0
|
0
|
|
|
|
0
|
die "Database name missing" unless $config->{db}->{name}; |
134
|
0
|
|
|
|
|
0
|
my $host; |
135
|
0
|
0
|
|
|
|
0
|
$host = 'host='. $config->{db}->{host} if $config->{db}->{host}; |
136
|
0
|
0
|
|
|
|
0
|
$host .= ';port='.$config->{db}->{port} if $config->{db}->{port}; |
137
|
0
|
|
|
|
|
0
|
my $dsn = qq(dbi:$config->{db}->{type}:dbname=$config->{db}->{name};$host); |
138
|
0
|
0
|
|
|
|
0
|
$dbh = DBI->connect($dsn, $config->{db}->{username}, $config->{db}->{password}, $config->{db}->{options}) or die "Error opening database: $config->{db}->{name}\n"; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
0
|
eval { |
142
|
0
|
|
|
|
|
0
|
foreach my $sql (split /;/, $schema) { |
143
|
0
|
0
|
|
|
|
0
|
$dbh->do($sql) or warn "Error executing SQL: $sql;\n"; |
144
|
|
|
|
|
|
|
} |
145
|
0
|
0
|
|
|
|
0
|
$dbh->commit unless $config->{db}->{options}->{AutoCommit}; |
146
|
|
|
|
|
|
|
}; |
147
|
|
|
|
|
|
|
|
148
|
0
|
0
|
|
|
|
0
|
if ($@) { |
149
|
0
|
|
|
|
|
0
|
warn "Transaction aborted: $@"; |
150
|
0
|
|
|
|
|
0
|
eval {$dbh->rollback}; |
|
0
|
|
|
|
|
0
|
|
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
0
|
$dbh->disconnect or die "Error closing database: $config->{db}->{name}\n"; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub parse { |
157
|
5
|
|
|
5
|
1
|
2062
|
my $self = shift; |
158
|
5
|
|
|
|
|
9
|
my $string = shift; |
159
|
|
|
|
|
|
|
|
160
|
5
|
50
|
|
|
|
17
|
if ($string) { |
161
|
5
|
|
|
|
|
16
|
my $config = $self->config; |
162
|
5
|
|
|
|
|
31
|
foreach my $expression (split /\./, $string) { |
163
|
30
|
|
|
|
|
43
|
my $schema; |
164
|
30
|
100
|
|
|
|
243
|
if ($expression =~ /\s+as\s+/) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
165
|
5
|
|
|
|
|
15
|
$schema = _as ($config, $expression); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
elsif ($expression =~ /vice[\s\-]+versa/) { |
168
|
5
|
|
|
|
|
15
|
$schema = _many_to_many ($config, $expression); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
elsif ($expression =~ /(has|have)\s+many/) { |
171
|
5
|
|
|
|
|
20
|
$schema = _has_many ($config, $expression); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
else { |
174
|
15
|
|
|
|
|
41
|
$schema = _has_a ($config, $expression); |
175
|
|
|
|
|
|
|
} |
176
|
30
|
50
|
|
|
|
155
|
$self->{SCHEMA} .= $schema if $schema; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
} |
179
|
5
|
|
50
|
|
|
56
|
return $self->{SCHEMA} || ''; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub show { |
183
|
1
|
|
|
1
|
1
|
736
|
my $self = shift; |
184
|
1
|
|
|
|
|
6
|
my $schema = $self->parse(@_); |
185
|
1
|
50
|
|
|
|
6
|
return unless $schema; |
186
|
1
|
|
|
|
|
2
|
my @pretty; |
187
|
|
|
|
|
|
|
|
188
|
1
|
|
|
|
|
9
|
foreach my $schema (split /;/, $schema) { |
189
|
9
|
100
|
|
|
|
30
|
if ($schema =~ /CREATE/) { |
190
|
5
|
|
|
|
|
37
|
$schema =~ s/^([^\(]+)\(/$1\(\n\t/g; |
191
|
5
|
|
|
|
|
67
|
$schema =~ s/\)([^\)]+)$/\n\)$1/g; |
192
|
5
|
|
|
|
|
71
|
$schema =~ s/([^\d]),([^\d])/$1,\n\t$2/g; |
193
|
5
|
|
|
|
|
11
|
$schema =~ s/\)$/\n)/; |
194
|
|
|
|
|
|
|
} |
195
|
9
|
|
|
|
|
28
|
push @pretty, $schema . ';'; |
196
|
|
|
|
|
|
|
} |
197
|
1
|
|
|
|
|
13
|
return join "\n\n", @pretty; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub _as { |
201
|
5
|
|
|
5
|
|
10
|
my $config = shift; |
202
|
5
|
|
|
|
|
17
|
my $expression = $config->{format}->{expression}->(shift); |
203
|
5
|
|
|
|
|
55
|
my ($table_name, $has, $foreign_table_name, $foreign_key) = split /\s+(has|have)\s+(.*)\s+as\s+(.*)/, $expression; |
204
|
5
|
50
|
33
|
|
|
44
|
return unless $table_name && $foreign_table_name && $foreign_key; |
|
|
|
33
|
|
|
|
|
205
|
5
|
|
|
|
|
21
|
$table_name = _normalise_table($config, $config->{format}->{table}->($table_name)); |
206
|
5
|
|
|
|
|
19
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($foreign_table_name)); |
207
|
5
|
|
|
|
|
13
|
$foreign_key = $config->{format}->{column}->($foreign_key); |
208
|
5
|
50
|
|
|
|
19
|
$foreign_key = $config->{foreign_key}->{singular} ? _singularise($foreign_key) : $foreign_key; |
209
|
5
|
|
|
|
|
14
|
$foreign_key .= $config->{foreign_key}->{suffix}; |
210
|
|
|
|
|
|
|
|
211
|
5
|
|
|
|
|
12
|
my $add_column = $config->{add_clause}; |
212
|
5
|
|
|
|
|
26
|
$add_column =~ s/\[%\s*table_name\s*%\]/$table_name/; |
213
|
5
|
|
|
|
|
11
|
$add_column =~ s/\[%\s*table_name\s*%\]/$table_name/; |
214
|
|
|
|
|
|
|
|
215
|
5
|
|
|
|
|
20
|
my $foreign_key_column = $foreign_key . ' ' . $config->{foreign_key}->{type}->{$config->{db}->{type}}; |
216
|
5
|
|
|
|
|
28
|
$add_column =~ s/\[%\s*clause\s*%\]/$foreign_key_column/; |
217
|
5
|
|
|
|
|
9
|
my $schema = $add_column; |
218
|
|
|
|
|
|
|
|
219
|
5
|
|
|
|
|
73
|
my $add_foreign_key = $config->{add_clause}; |
220
|
5
|
|
|
|
|
24
|
$add_foreign_key =~ s/\[%\s*table_name\s*%\]/$table_name/; |
221
|
5
|
|
|
|
|
14
|
my $foreign_key_clause = _generate_foreign_key_clause($config, $foreign_key, $foreign_table_name); |
222
|
5
|
|
|
|
|
26
|
$add_foreign_key =~ s/\[%\s*clause\s*%\]/$foreign_key_clause/; |
223
|
5
|
|
|
|
|
48
|
$schema .= $add_foreign_key; |
224
|
|
|
|
|
|
|
|
225
|
5
|
|
|
|
|
18
|
return $schema; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _many_to_many { |
229
|
5
|
|
|
5
|
|
13
|
my $config = shift; |
230
|
5
|
|
|
|
|
14
|
my $expression = $config->{format}->{expression}->(shift); |
231
|
5
|
|
|
|
|
79
|
$expression =~ s/,\s+vice[\s\-]+versa//; |
232
|
5
|
|
|
|
|
48
|
my ($table_name, $has, $foreign_table_name) = split /\s*(has|have)\s+many\s*/, $expression; |
233
|
5
|
50
|
33
|
|
|
28
|
return unless $table_name && $foreign_table_name; |
234
|
5
|
|
|
|
|
17
|
$table_name = _normalise_table($config, $config->{format}->{table}->($table_name)); |
235
|
5
|
|
|
|
|
18
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($foreign_table_name)); |
236
|
5
|
|
|
|
|
44
|
my $map_table = $config->{map_table}; |
237
|
5
|
|
|
|
|
33
|
$map_table =~ s/\[%\s*table_name\s*%\]/$table_name/; |
238
|
5
|
|
|
|
|
26
|
$map_table =~ s/\[%\s*foreign_table_name\s*%\]/$foreign_table_name/; |
239
|
|
|
|
|
|
|
|
240
|
5
|
|
|
|
|
20
|
my $schema = $config->{table}->{$config->{db}->{type}}; |
241
|
5
|
|
|
|
|
26
|
$schema =~ s/\[%\s*table_name\s*%\]/$map_table/; |
242
|
|
|
|
|
|
|
|
243
|
5
|
|
|
|
|
9
|
my $foreign_keys; |
244
|
5
|
|
|
|
|
26
|
my @columns = ($config->{primary_key}->{name} . ' ' . $config->{primary_key}->{type}->{$config->{db}->{type}}); |
245
|
|
|
|
|
|
|
|
246
|
5
|
|
|
|
|
14
|
foreach my $table ($table_name, $foreign_table_name) { |
247
|
10
|
50
|
|
|
|
36
|
my $foreign_key = $config->{foreign_key}->{singular} ? _singularise($table) : $table; |
248
|
10
|
|
|
|
|
23
|
$foreign_key .= $config->{foreign_key}->{suffix}; |
249
|
10
|
|
|
|
|
28
|
$foreign_keys->{$foreign_key} = $table; |
250
|
10
|
|
|
|
|
52
|
push @columns, $foreign_key . ' ' . $config->{foreign_key}->{type}->{$config->{db}->{type}}; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
5
|
|
|
|
|
10
|
foreach my $foreign_key (keys %{$foreign_keys}) { |
|
5
|
|
|
|
|
19
|
|
254
|
10
|
|
|
|
|
23
|
push @columns, _generate_foreign_key_clause($config, $foreign_key, $foreign_keys->{$foreign_key}); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
5
|
|
|
|
|
24
|
my $schema_columns = join ',', @columns; |
258
|
5
|
|
|
|
|
29
|
$schema =~ s/\[%\s*columns\s*%\]/$schema_columns/; |
259
|
5
|
|
|
|
|
28
|
return $schema; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub _has_many { |
263
|
5
|
|
|
5
|
|
9
|
my $config = shift; |
264
|
5
|
|
|
|
|
18
|
my $expression = $config->{format}->{expression}->(shift); |
265
|
5
|
|
|
|
|
49
|
my ($table_name, $has, $foreign_table_name) = split /\s*(has|have)\s+many\s*/, $expression; |
266
|
5
|
50
|
33
|
|
|
31
|
return unless $table_name && $foreign_table_name; |
267
|
5
|
|
|
|
|
19
|
$table_name = _normalise_table($config, $config->{format}->{table}->($table_name)); |
268
|
5
|
|
|
|
|
15
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($foreign_table_name)); |
269
|
5
|
|
|
|
|
13
|
my $add_column = $config->{add_clause}; |
270
|
5
|
|
|
|
|
25
|
$add_column =~ s/\[%\s*table_name\s*%\]/$foreign_table_name/; |
271
|
|
|
|
|
|
|
|
272
|
5
|
50
|
|
|
|
21
|
my $foreign_key = $config->{foreign_key}->{singular} ? _singularise($table_name) : $table_name; |
273
|
5
|
|
|
|
|
52
|
$foreign_key .= $config->{foreign_key}->{suffix}; |
274
|
|
|
|
|
|
|
|
275
|
5
|
|
|
|
|
20
|
my $foreign_key_column = $foreign_key . ' ' . $config->{foreign_key}->{type}->{$config->{db}->{type}}; |
276
|
5
|
|
|
|
|
26
|
$add_column =~ s/\[%\s*clause\s*%\]/$foreign_key_column/; |
277
|
5
|
|
|
|
|
9
|
my $schema = $add_column; |
278
|
|
|
|
|
|
|
|
279
|
5
|
|
|
|
|
9
|
my $add_foreign_key = $config->{add_clause}; |
280
|
5
|
|
|
|
|
24
|
$add_foreign_key =~ s/\[%\s*table_name\s*%\]/$foreign_table_name/; |
281
|
|
|
|
|
|
|
|
282
|
5
|
|
|
|
|
12
|
my $foreign_key_clause = _generate_foreign_key_clause($config, $foreign_key, $table_name); |
283
|
5
|
|
|
|
|
26
|
$add_foreign_key =~ s/\[%\s*clause\s*%\]/$foreign_key_clause/; |
284
|
5
|
|
|
|
|
13
|
$schema .= $add_foreign_key; |
285
|
|
|
|
|
|
|
|
286
|
5
|
|
|
|
|
26
|
return $schema; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub _has_a { |
290
|
20
|
|
|
20
|
|
29
|
my $config = shift; |
291
|
20
|
|
|
|
|
52
|
my $expression = $config->{format}->{expression}->(shift); |
292
|
20
|
|
|
|
|
157
|
my ($table_name, $has, $columns) = ($expression =~ /^([\w_\-0-9\s]+)\s+(has|have)\s+(.*)$/); |
293
|
20
|
50
|
33
|
|
|
110
|
return unless $table_name && $columns; |
294
|
|
|
|
|
|
|
|
295
|
20
|
|
|
|
|
23
|
my ($schema, $foreign_keys, $foreign_table_name, $foreign_table_columns, $custom_columns); |
296
|
20
|
|
|
|
|
38
|
my $foreign_key_suffix = $config->{foreign_key}->{suffix}; |
297
|
20
|
|
|
|
|
49
|
my $table = {name => _normalise_table($config, $config->{format}->{table}->($table_name))}; |
298
|
|
|
|
|
|
|
|
299
|
20
|
|
|
|
|
31
|
push @{$table->{columns}}, {name => $config->{primary_key}->{name}, type => $config->{primary_key}->{type}->{$config->{db}->{type}}}; |
|
20
|
|
|
|
|
120
|
|
300
|
|
|
|
|
|
|
|
301
|
20
|
|
|
|
|
79
|
while ($columns =~ /[()]/) { |
302
|
35
|
|
|
|
|
4776
|
($foreign_table_name, $foreign_table_columns) = ($columns =~ /([\w_\-0-9\s]+)\s*($RE{balanced}{-parens=>'()'})/); |
303
|
35
|
|
|
|
|
5948
|
($foreign_table_columns) = ($foreign_table_columns =~ /\((.*)\)/); |
304
|
|
|
|
|
|
|
|
305
|
35
|
100
|
|
|
|
125
|
if($foreign_table_columns =~ /^\s*(has|have)/) { |
306
|
5
|
|
|
|
|
29
|
$schema .= _has_a($config, join ' ', ($foreign_table_name , $foreign_table_columns)); |
307
|
5
|
|
|
|
|
22
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($foreign_table_name)); |
308
|
5
|
50
|
|
|
|
20
|
my $foreign_key = $config->{foreign_key}->{singular} ? _singularise($foreign_table_name) : $foreign_table_name; |
309
|
5
|
|
|
|
|
11
|
$foreign_key .= $foreign_key_suffix; |
310
|
5
|
|
|
|
|
13
|
$foreign_keys->{$foreign_key} = $foreign_table_name; |
311
|
5
|
|
|
|
|
28
|
$columns =~ s/(\b[\w_\-0-9\s]*)\b\s*($RE{balanced}{-parens=>'()'})/$foreign_key/; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
else { |
314
|
30
|
|
|
|
|
83
|
$foreign_table_name = $config->{format}->{column}->($foreign_table_name); |
315
|
|
|
|
|
|
|
|
316
|
30
|
100
|
|
|
|
128
|
if ($foreign_table_columns =~ /^reference/) { |
|
|
50
|
|
|
|
|
|
317
|
5
|
|
|
|
|
10
|
my $foreign_key = $foreign_table_name; |
318
|
5
|
|
|
|
|
27
|
my ($reference_table) = ($foreign_table_columns =~ /^references?\s+([\w_\-0-9\s]+)$/); |
319
|
|
|
|
|
|
|
|
320
|
5
|
50
|
|
|
|
16
|
if ($reference_table) { |
321
|
5
|
|
|
|
|
16
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($reference_table)); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
else { |
324
|
0
|
|
|
|
|
0
|
$foreign_table_name =~ s/$foreign_key_suffix$//; |
325
|
0
|
|
|
|
|
0
|
$foreign_table_name = _normalise_table($config, $config->{format}->{table}->($foreign_table_name)); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
5
|
|
|
|
|
19
|
$foreign_keys->{$foreign_key} = $foreign_table_name; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
elsif (exists $config->{columns}->{$foreign_table_columns}) { |
331
|
25
|
|
|
|
|
84
|
$custom_columns->{$foreign_table_name} = $config->{columns}->{$foreign_table_columns}; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
30
|
|
|
|
|
139
|
$columns =~ s/([\w_\-0-9]*)\s*($RE{balanced}{-parens=>'()'})/$1/; # clean it for the while loop |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
20
|
|
|
|
|
2619
|
foreach my $column (split /\s*,\s*/, $columns) { |
339
|
80
|
|
|
|
|
184
|
$column = $config->{format}->{column}->($column); |
340
|
80
|
100
|
|
|
|
177
|
if (exists $foreign_keys->{$column}) { |
341
|
10
|
|
|
|
|
14
|
push @{$table->{columns}}, {name => $column, type => $config->{foreign_key}->{type}->{$config->{db}->{type}}}; |
|
10
|
|
|
|
|
67
|
|
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
else { |
344
|
70
|
100
|
|
|
|
191
|
if (exists $custom_columns->{$column}) { |
|
|
100
|
|
|
|
|
|
345
|
25
|
|
|
|
|
28
|
push @{$table->{columns}}, {name => $column, type => $custom_columns->{$column}}; |
|
25
|
|
|
|
|
111
|
|
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
elsif (exists $config->{columns}->{$column}) { |
348
|
20
|
|
|
|
|
26
|
push @{$table->{columns}}, {name => $column, type => $config->{columns}->{$column}}; |
|
20
|
|
|
|
|
111
|
|
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
else { |
351
|
25
|
|
|
|
|
28
|
my $column_type; |
352
|
25
|
|
|
|
|
29
|
DEF: foreach my $column_key (keys %{$config->{columns}}) { |
|
25
|
|
|
|
|
119
|
|
353
|
310
|
100
|
|
|
|
2632
|
if ($column =~ /$column_key/) { |
354
|
|
|
|
|
|
|
# first match |
355
|
20
|
|
|
|
|
28
|
$column_type = $column_key; |
356
|
20
|
|
|
|
|
43
|
last DEF; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
25
|
100
|
|
|
|
81
|
if ($column_type) { |
361
|
20
|
|
|
|
|
29
|
push @{$table->{columns}}, {name => $column, type => $config->{columns}->{$column_type}}; |
|
20
|
|
|
|
|
115
|
|
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
else { |
364
|
5
|
|
|
|
|
9
|
push @{$table->{columns}}, {name => $column, type => $config->{columns}->{name}}; # default |
|
5
|
|
|
|
|
28
|
|
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
20
|
|
|
|
|
39
|
my $schema_columns = [map {$_->{name} . ' ' . $_->{type}} @{$table->{columns}}]; |
|
100
|
|
|
|
|
275
|
|
|
20
|
|
|
|
|
43
|
|
371
|
|
|
|
|
|
|
|
372
|
20
|
|
|
|
|
31
|
foreach my $foreign_key (keys %{$foreign_keys}) { |
|
20
|
|
|
|
|
61
|
|
373
|
10
|
|
|
|
|
13
|
push @{$schema_columns}, _generate_foreign_key_clause($config, $foreign_key, $foreign_keys->{$foreign_key}); |
|
10
|
|
|
|
|
34
|
|
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
20
|
|
|
|
|
33
|
my $schema_columns_string = join ',', @{$schema_columns}; |
|
20
|
|
|
|
|
63
|
|
377
|
|
|
|
|
|
|
|
378
|
20
|
|
|
|
|
60
|
$schema .= $config->{table}->{$config->{db}->{type}}; |
379
|
20
|
|
|
|
|
180
|
$schema =~ s/\[%\s*table_name\s*%\]/$table->{name}/; |
380
|
20
|
|
|
|
|
102
|
$schema =~ s/\[%\s*columns\s*%\]/$schema_columns_string/; |
381
|
|
|
|
|
|
|
|
382
|
20
|
|
|
|
|
193
|
return $schema; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
sub _singularise { |
386
|
|
|
|
|
|
|
# based on Rose::DB::Object::ConventionManager |
387
|
85
|
|
|
85
|
|
122
|
my $word = shift; |
388
|
85
|
|
|
|
|
170
|
$word =~ s/ies$/y/i; |
389
|
85
|
50
|
|
|
|
215
|
return $word if ($word =~ s/ses$/s/); |
390
|
85
|
50
|
|
|
|
256
|
return $word if($word =~ /[aeiouy]ss$/i); |
391
|
85
|
|
|
|
|
178
|
$word =~ s/s$//i; |
392
|
85
|
|
|
|
|
207
|
return $word; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub _generate_foreign_key_clause { |
396
|
30
|
|
|
30
|
|
59
|
my ($config, $foreign_key, $reference_table) = @_; |
397
|
30
|
|
|
|
|
56
|
my $foreign_key_clause = $config->{foreign_key}->{clause}; |
398
|
30
|
|
|
|
|
144
|
$foreign_key_clause =~ s/\[%\s*foreign_key\s*%\]/$foreign_key/; |
399
|
30
|
|
|
|
|
144
|
$foreign_key_clause =~ s/\[%\s*reference_table\s*%\]/$reference_table/; |
400
|
30
|
|
|
|
|
183
|
$foreign_key_clause =~ s/\[%\s*reference_primary_key\s*%\]/$config->{primary_key}->{name}/; |
401
|
30
|
|
|
|
|
121
|
return $foreign_key_clause; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
sub _normalise_table { |
405
|
60
|
|
|
60
|
|
107
|
my ($config, $table) = @_; |
406
|
60
|
|
|
|
|
149
|
my $table_name; |
407
|
|
|
|
|
|
|
|
408
|
60
|
50
|
|
|
|
154
|
if ($config->{db}->{tables_are_singular}) { |
409
|
60
|
|
|
|
|
104
|
$table_name = _singularise($table); |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
else { |
412
|
0
|
|
|
|
|
0
|
$table_name = Lingua::EN::Inflect::PL(_singularise($table)); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
60
|
100
|
|
|
|
234
|
return $config->{db}->{table_prefix} . $table_name if defined $config->{db}->{table_prefix}; |
416
|
36
|
|
|
|
|
98
|
return $table_name; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
1; |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
__END__ |