File Coverage

blib/lib/DBR/Config/SpecLoader.pm
Criterion Covered Total %
statement 133 168 79.1
branch 48 102 47.0
condition 2 6 33.3
subroutine 15 16 93.7
pod 0 3 0.0
total 198 295 67.1


line stmt bran cond sub pod time code
1             # the contents of this file are Copyright (c) 2009 Daniel Norman
2             # This program is free software; you can redistribute it and/or
3             # modify it under the terms of the GNU General Public License as
4             # published by the Free Software Foundation.
5              
6             package DBR::Config::SpecLoader;
7              
8 18     18   13550 use strict;
  18         46  
  18         829  
9              
10 18     18   104 use base 'DBR::Common';
  18         41  
  18         1496  
11              
12 18     18   121 use DBR::Config::Trans;
  18         42  
  18         454  
13 18     18   110 use DBR::Config::Relation;
  18         40  
  18         547  
14 18     18   106 no warnings 'deprecated';
  18         49  
  18         1068  
15 18     18   111 use DBR::Config::ScanDB;
  18         40  
  18         465  
16 18     18   19088 use Switch;
  18         771002  
  18         192  
17              
18             my $trans_defs = DBR::Config::Trans->list_translators or die 'Failed to get translator list';
19             my %trans_lookup; map {$trans_lookup{ uc($_->{name}) } = $_} @$trans_defs;
20              
21             my $relationtype_defs = DBR::Config::Relation->list_types or die 'Failed to get relationship type list';
22             my %relationtype_lookup; map {$relationtype_lookup{ uc($_->{name}) } = $_} @$relationtype_defs;
23              
24              
25             sub new {
26 17     17 0 51 my( $package ) = shift;
27 17         317 my %params = @_;
28 17         151 my $self = {
29             session => $params{session},
30             conf_instance => $params{conf_instance},
31             dbr => $params{dbr},
32             };
33              
34 17         102 bless( $self, $package );
35              
36 17 50       695 return $self->_error('session object must be specified') unless $self->{session};
37 17 50       82 return $self->_error('conf_instance object must be specified') unless $self->{conf_instance};
38              
39 17         113 return( $self );
40             }
41              
42             sub process_spec{
43 17     17 0 50 my $self = shift;
44 17         42 my $specs = shift;
45              
46 17 50       230 my $dbrh = $self->{conf_instance}->connect or die "Failed to connect to config db";
47              
48 17         108 $dbrh->begin();
49              
50 17         41 my %SCANS;
51             my %SCHEMA_IDS;
52 0         0 my $sortval;
53 17         73 foreach my $spec ( @$specs ){
54 177         748 my $oldtable = $spec->{table};
55 177 50       1179 if ( $spec->{table} =~ s/^(.*?)\.// ){
56 0   0     0 $spec->{schema} ||= $1;
57             }
58              
59 177 50       543 map {$spec->{ $_ } or die "Invalid Spec row: Missing $_"} qw'schema table field cmd';
  708         4950  
60              
61            
62 177 100       1125 if( ! $SCANS{ $spec->{schema} }++ ){
63             # HERE - THIS \/ is wrong. Fix it. Should be asking the schema object for an instance
64 17 50       144 my $scan_instance = $self->{dbr}->get_instance( $spec->{schema} ) or die "No config found for scandb $spec->{schema}";
65              
66 17         595 my $scanner = DBR::Config::ScanDB->new(
67             session => $self->{dbr}->session,
68             conf_instance => $self->{conf_instance},
69             scan_instance => $scan_instance,
70             );
71              
72              
73 17 50       267 $scanner->scan() or die "Failed to scan $spec->{schema}";
74             }
75              
76 177 50       4028 my $schema = new DBR::Config::Schema(session => $self->{session}, handle => $spec->{schema}) or die "Schema $spec->{schema} not found";
77 177 50       887 my $table = $schema->get_table( $spec->{table} ) or die "$spec->{table} not found in schema\n";
78 177 50       11504 my $field = $table->get_field ( $spec->{field} ) or die "$spec->{table}.$spec->{field} not found\n";
79 177         2050 $SCHEMA_IDS{ $schema->schema_id } = 1;
80 177         334 switch ( uc($spec->{cmd}) ){
  177         433  
  177         1786  
  0         0  
81 177 100       4721 case 'TRANSLATOR' { $self->_do_translator( $schema, $table, $field, $spec ) }
  37         846  
  37         1029  
  37         1001  
  0         0  
  0         0  
  0         0  
82 140 100       3260 case 'RELATION' { $self->_do_relation ( $schema, $table, $field, $spec ) }
  24         456  
  24         134  
  24         488  
  0         0  
  0         0  
  0         0  
83 116 100       2232 case 'REGEX' { $self->_do_regex ( $schema, $table, $field, $spec ) }
  9         218  
  9         66  
  9         225  
  0         0  
  0         0  
  0         0  
84 107 50       1655 case 'ENUMOPT' { $self->_do_enumopt ( $schema, $table, $field, $spec, ++$sortval ) }
  107         1449  
  107         508  
  107         4633  
  0         0  
  0         0  
  0         0  
85 0 0       0 case 'DEFAULT' { $self->_do_default ( $schema, $table, $field, $spec ) }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
86 0         0 else { die "Invalid spec: unknown command $spec->{cmd}"}
87             }
88             }
89              
90 17         123 $dbrh->commit();
91            
92 17         337 foreach my $schema_id ( keys %SCHEMA_IDS ) {
93             #HACK - the SpecLoader should load up the in-memory representation at the same time
94 17 50       250 DBR::Config::Schema->load(
95             session => $self->{session},
96             schema_id => $schema_id,
97             instance => $self->{conf_instance},
98             ) or die "Failed to reload schema";
99             }
100            
101 17         114 return 1;
102             }
103              
104              
105             # Did this one the new way cus it was easy, the rest will be redone at some point
106             sub _do_translator {
107 37     37   88 my ($self, $schema, $table, $field, $spec) = @_;
108              
109 37 50       207 my $transname = uc($spec->{translator}) or die "Missing parameter: translator";
110 37 50       186 my $new_trans = $trans_lookup{ uc($transname) } or die "Invalid translator '$spec->{translator}'";
111              
112 37 50       214 $field->update_translator($transname) or die "Failed to update field translator for $spec->{table}.$spec->{field}";
113              
114 37         115 return 1;
115              
116             }
117              
118             sub _do_regex {
119 9     9   29 my ($self, $schema, $table, $field, $spec) = @_;
120              
121 9 50       55 $spec->{regex} or die "Missing parameter: regex";
122 9 50       102 $field->update_regex($spec->{regex}) or die "Failed to update field regex for $spec->{table}.$spec->{field}";
123              
124 9         31 return 1;
125              
126             }
127             sub _do_default {
128 0     0   0 my ($self, $schema, $table, $field, $spec) = @_;
129              
130 0 0       0 defined($spec->{value}) or die "Missing parameter: value";
131 0 0       0 $field->update_default($spec->{value}) or die "Failed to update field default for $spec->{table}.$spec->{field}";
132              
133 0         0 return 1;
134              
135             }
136              
137             sub _do_relation {
138 24     24   59 my ($self, $schema, $table, $field, $spec) = @_;
139              
140 24 50       57 map { $spec->{$_} or die("Parameter '$_' must be specified") } qw'relname reltable relfield type reverse_name';
  120         412  
141              
142              
143 24         460 my ($toschema_name) = $spec->{reltable} =~ /^(.*?)\./;
144              
145 24         47 my $toschema = $schema;
146 24 50       124 if ( $spec->{reltable} =~ s/^(.*?)\.// ){
147 0         0 my $toschema_name = $1;
148 0 0       0 $toschema = new DBR::Config::Schema(session => $self->{session}, handle => $toschema_name )
149             or die "Schema $spec->{schema} not found";
150             }
151              
152 24 50       1266 my $totable = $toschema->get_table( $spec->{reltable} ) or die "$spec->{reltable} not found in schema\n";
153 24 50       143 my $tofield = $totable ->get_field( $spec->{relfield} ) or die "$spec->{reltable}.$spec->{relfield} not found\n";
154              
155 24 50       144 my $type = $relationtype_lookup{ uc ($spec->{type}) } or die "Invalid relationship type '$spec->{type}'";
156 24         86 my $type_id = $type->{type_id};
157              
158 24 50       189 my $dbrh = $self->{conf_instance}->connect or die "Failed to connect to config db";
159              
160 24         173 my $relationship = $dbrh->select(
161             -table => 'dbr_relationships',
162             -fields => 'relationship_id from_name from_table_id from_field_id to_name to_table_id to_field_id type',
163             -where => {
164             from_table_id => ['d',$table->table_id],
165             to_name => $spec->{relname}
166             },
167             -single => 1,
168             );
169 24 50       171 defined $relationship or die('Failed to select relationships');
170              
171 24 50       84 if ($relationship){
172 0 0       0 $dbrh->update(
173             -table => 'dbr_relationships',
174             -fields => {
175             from_field_id => ['d',$field->field_id],
176             from_name => $spec->{reverse_name},
177              
178             to_table_id => ['d',$totable->table_id],
179             to_field_id => ['d',$tofield->field_id],
180              
181             type => ['d',$type_id],
182             },
183             -where => { relationship_id => ['d', $relationship->{relationship_id} ]},
184             ) or die "Failed to update relationship";
185             }else{
186 24 50       183 $dbrh->insert(
187             -table => 'dbr_relationships',
188             -fields => {
189             from_table_id => ['d',$table->table_id],
190             from_field_id => ['d',$field->field_id],
191             from_name => $spec->{reverse_name},
192              
193             to_field_id => ['d',$tofield->field_id],
194             to_table_id => ['d',$totable->table_id],
195             to_name => $spec->{relname},
196              
197             type => ['d',$type_id],
198             },
199             ) or die "Failed to insert relationship";
200             }
201              
202 24         276 return 1;
203             }
204              
205              
206             #This needs to be made smarter
207             sub _do_enumopt {
208 107     107   256 my ($self, $schema, $table, $field, $spec, $sortval) = @_;
209              
210 107 50       224 map { length($spec->{$_}) or die("Parameter '$_' must be specified") } qw'handle name';
  214         1037  
211              
212 107         269 my $override;
213              
214 107 100 66     826 if (!length($spec->{override_id}) or uc($spec->{override_id}) eq 'NULL'){
215 24         41 $override = undef;
216             }else{
217 83         291 $override = [ 'd' => $spec->{override_id} ];
218             }
219              
220 107         502 my %where = (
221             handle => $spec->{handle},
222             override_id => $override
223             );
224              
225 107 50       588 my $dbrh = $self->{conf_instance}->connect or die "Failed to connect to config db";
226              
227 107         888 my $enum = $dbrh->select(
228             -table => 'enum',
229             -fields => 'enum_id handle name override_id',
230             -where => \%where,
231             -single => 1,
232             );
233 107 50       610 defined $enum or die "Failed to select from enum";
234              
235 107         415 my $enum_id;
236             my $map;
237 107 50       582 if($enum){
238 0         0 $enum_id = $enum->{enum_id};
239 0 0       0 $dbrh->update(
240             -table => 'enum',
241             -fields => { name => $spec->{name} },
242             -where => { enum_id => ['d', $enum->{enum_id} ] },
243             -single => 1,
244             ) or die "Failed to update enum";
245              
246 0         0 $map = $dbrh->select(
247             -table => 'enum_map',
248             -fields => 'row_id field_id enum_id sortval',
249             -where => {
250             enum_id => [ 'd', $enum_id ],
251             field_id => [ 'd', $field->field_id ]
252             },
253             -single => 1,
254             );
255 0 0       0 defined ($map) or die "Failed to select from enum_map";
256             }else{
257 107 50       1409 $enum_id = $dbrh->insert(
258             -table => 'enum',
259             -fields => {
260             handle => $spec->{handle},
261             override_id => $override,
262             name => $spec->{name}
263             },
264             ) or die "Failed to insert into enum";
265             }
266              
267              
268              
269 107 50       488 if($map){
270 0 0       0 $dbrh->update(
271             -table => 'enum_map',
272             -fields => { sortval => ['d',$sortval] },
273             -where => { row_id => ['d', $map->{row_id} ] },
274             ) or die "Failed to update enum_map";
275             }else{
276 107 50       1189 $dbrh->insert(
277             -table => 'enum_map',
278             -fields => {
279             enum_id => [ 'd', $enum_id ],
280             field_id => [ 'd', $field->field_id ],
281             sortval => [ 'd', $sortval ]
282             },
283             ) or die "Failed to insert into enum";
284             }
285              
286 107         1388 return 1;
287             }
288              
289              
290             sub parse_file{
291 17     17 0 45 my $self = shift;
292 17         45 my $filename = shift;
293 17 50       4841 open (my $fh, "<$filename") or die "Failed to open $filename";
294 17         486 my @out;
295 17         10873 while( my $line = <$fh>){
296 177         637 $self->_parse_line(\@out,$line);
297             }
298              
299 17         1268 return \@out;
300             }
301              
302             sub _parse_line{
303 177     177   254 my $self = shift;
304 177         417 my $out = shift;
305 177         412 my $line = shift;
306 177         614 chomp $line;
307              
308 177 50       1128 next if $line =~ /^\s*\#/; # skip comments
309              
310 177         1065 my @parts = split(/\t/,$line);
311 177 50       450 return 1 unless @parts;
312              
313 177         211 my %params;
314 177         2636 foreach my $part (@parts){
315 1221         10934 my ($field,$value) = $part =~ /^(.*?)\s*\=\s*(.*)$/;
316              
317 1221 50       4118 if ( length($field) ){
318 1221         8889 $params { lc($field) } = $value;
319             }
320             }
321 177 50       517 if (%params){ # did we get anything?
322 177         384 push @$out, \%params;
323             }
324              
325 177         1839 return 1;
326             }
327              
328              
329             1;