File Coverage

blib/lib/NoSQL/PL2SQL/Node.pm
Criterion Covered Total %
statement 9 147 6.1
branch 0 90 0.0
condition 0 60 0.0
subroutine 3 15 20.0
pod 0 12 0.0
total 12 324 3.7


line stmt bran cond sub pod time code
1             package NoSQL::PL2SQL::Node ;
2              
3 2     2   76397 use 5.008009;
  2         9  
  2         84  
4 2     2   9 use strict;
  2         4  
  2         112  
5 2     2   12 use warnings;
  2         8  
  2         4762  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14              
15             # This allows declaration use NoSQL::PL2SQL::Node ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18             our %EXPORT_TAGS = ( 'all' => [ qw() ] ) ;
19              
20             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ) ;
21              
22             our @EXPORT = qw() ;
23              
24             our $VERSION = '0.07';
25              
26             # Preloaded methods go here.
27              
28             ## The objectid is optional. If objectid is assigned automatically,
29             ## objectid = recno of perldata element. Which is otherwise the last
30             ## element to be inserted.
31             sub factory {
32 0 0   0 0   shift @_ if $_[0] eq __PACKAGE__ ;
33 0           my $dsn = shift ;
34 0 0         my $objectid = ! defined $_[0]? shift( @_ ):
    0          
35             ref $_[0]? undef: shift( @_ ) ;
36 0           my $o = shift ;
37 0 0         my $ref = @_? shift( @_ ): '' ;
38              
39 0   0       my $globals = { objecttype => $ref || ref $o } ;
40 0 0         $globals->{objectid} = $objectid if defined $objectid ;
41 0           my @nodes = xml2sql( XML::Parser::Nodes->pl2xml( $o ), $globals ) ;
42 0 0 0       return @nodes unless $dsn && $dsn->dbconnected ;
43              
44 0 0         unless ( defined $objectid ) {
45 0           $nodes[-1]->sql( $dsn ) ;
46 0           $objectid = $nodes[-1]->{sql}->{id} ;
47 0           map { $_->{sql}->{objectid} = $objectid } @nodes ;
  0            
48             }
49              
50 0           insertall( $dsn, combine( @nodes ) ) ;
51 0           return $objectid ;
52             }
53              
54             sub xml2sql {
55 0 0   0 0   shift @_ if $_[0] eq __PACKAGE__ ;
56 0           my $parent = undef ;
57              
58 0 0         $parent = pop if @_ > 3 ; ## ARRAY
59 0 0         my $globals = pop if ref $_[-1] eq 'HASH' ; ## HASH
60 0           my $node = pop ; ## XML::Parser::Nodes
61 0           my $key = pop ; ## scalar
62              
63 0   0       $globals ||= {} ;
64              
65 0           my $child = [ $key, $node ] ;
66 0           my @out = map { xml2sql( @$_, $globals, $child ) }
  0            
67             $node->childnodes() ;
68 0 0         push @out, new( __PACKAGE__, @$child, $parent, $globals ) if $parent ;
69 0           return @out ;
70             }
71              
72             my @nok ; ## debugging artifact
73              
74             my %typemap = (
75             integer => "intdata",
76             double => "doubledata",
77             string => "stringdata",
78             ) ;
79              
80             ## From the schema
81             my @strings = qw(
82             stringdata
83             textkey
84             objecttype
85             blesstype
86             reftype
87             stringrepr
88             ) ;
89              
90             my %strings = map { $_ => 1 } @strings ;
91              
92             sub typemap {
93 0 0   0 0   my @rv = map { $typemap{ typeis( $_ ) } || '' } @_ ;
  0            
94 0 0         return wantarray? @rv: $rv[0] ;
95             }
96              
97             sub new {
98 0     0 0   my $package = shift ;
99 0           my $self = {} ;
100              
101 0           $self->{key} = shift ;
102 0           $self->{xml} = shift ;
103 0           my $parent = shift ;
104 0           my $globals = shift ;
105              
106 0           $self->{parenttype} = $parent->[0] ;
107 0   0       $self->{parentid} = $parent->[1]->getattributes->{memory_address}
108             || $parent->[0] || $self->{key} ;
109              
110 0           my $attribs = $self->{xml}->getattributes ;
111              
112 0           $self->{sql} = { %$globals } ;
113 0           my @strings = ( $self ) ;
114 0           my @text = $self->{xml}->gettext ;
115              
116             ## Needs to be a reliable detection of legitimate XML data
117             # if ( grep $_ eq $self->{key}, qw( item string scalar scalarref ) ) {
118 0 0         if ( @text == 1 ) {
119 0           my $sv = $text[0] ;
120 0           my $svtype = typemap( $text[0] ) ;
121            
122 0 0         if ( $svtype eq 'stringdata' ) {
    0          
123 0           my @buff = stringsplit( $text[0] ) ;
124 0           $self->{sql}->{$svtype} = shift @buff ;
125            
126 0           push @strings, map { stringfactory( $self,
  0            
127             reftype => 'string',
128             defined => 1,
129             $svtype => $_,
130             %$globals ) } @buff ;
131             }
132             elsif ( $svtype ) {
133 0           $self->{sql}->{$svtype} = $text[0] ;
134             }
135             else {
136 0           push @nok, $text[0] ;
137             }
138            
139 0           my $text = $self->{xml}->gettext ;
140 0           $text =~ s/'/\\'/sg ;
141 0           $self->{sql}->{stringrepr} = $text ;
142             }
143              
144 0           $self->{sql}->{reftype} = $self->{key} ;
145 0 0         $self->{sql}->{blesstype} = $attribs->{blessed_package}
146             if $attribs->{blessed_package} ;
147              
148 0 0 0       $self->{sql}->{textkey} = $attribs->{key}
      0        
149             if ! exists $self->{sql}->{textkey}
150             && exists $attribs->{key}
151             && $self->{parenttype} eq 'hashref' ;
152 0 0 0       $self->{sql}->{intkey} = $attribs->{key}
      0        
153             if ! exists $self->{sql}->{intkey}
154             && exists $attribs->{key}
155             && $self->{parenttype} eq 'arrayref' ;
156 0   0       $self->{sql}->{defined} = ! ( exists $attribs->{defined}
157             && $attribs->{defined} eq 'false' ) ;
158            
159 0           map { bless $_, $package } @strings ;
  0            
160 0           return reverse @strings ;
161             }
162              
163             sub stringsplit {
164 0 0   0 0   shift @_ if $_[0] eq __PACKAGE__ ;
165 0           my $text = shift ;
166              
167 0           my @buff = () ;
168 0           push @buff, $1 while $text =~ s/^(.{512})//s ;
169 0 0         push @buff, $text if length $text ;
170 0 0         return @buff? @buff: ('') ;
171             }
172              
173             sub stringfactory {
174 0     0 0   my $self = shift ;
175 0           my $out = { key => 'string', xml => $self->{xml}, sql => { @_ } } ;
176 0           return bless $out, ref $self ;
177             }
178              
179             sub reference {
180 0     0 0   my $self = shift ;
181 0           my $sql = shift ;
182              
183 0 0         map { $self->{sql}->{$_} = $sql->{$_} }
  0            
184             qw( blesstype reftype )
185             if ref $sql ;
186 0           return $self->{sql}->{reftype} ;
187             }
188              
189             sub memory {
190 0     0 0   my $self = shift ;
191 0 0         return undef unless $self->{xml} ;
192 0           return $self->{xml}->getattributes->{memory_address} ;
193             }
194              
195             sub parentid {
196 0     0 0   my $self = shift ;
197 0 0 0       return 'string' if exists $self->{key} && $self->{key} eq 'string' ;
198 0 0         return $self->{combine}?
199             $self->{combine}->{parentid}:
200             $self->{parentid} ;
201             }
202              
203             sub sql {
204 0     0 0   my $self = shift ;
205 0           my $dsn = shift ;
206              
207 0 0         return warn unless $dsn ;
208              
209 0 0         my $combine = exists $self->{combine}?
210             $self->{combine}->{sql}: {} ;
211              
212 0           my @nvp = @_ ;
213 0 0         push @nvp, map { $_ => exists $combine->{$_}?
  0            
214             $combine->{$_}:
215             $self->{sql}->{$_}
216 0           } keys %$combine, keys %{ $self->{sql} } ;
217              
218 0           my %nvp = @nvp ;
219 0 0         $nvp{reftype} = $self->{sql}->{reftype}
220             if exists $self->{sql}->{reftype} ;
221 0 0         my $id = exists $nvp{id}? $nvp{id}: undef ;
222              
223 0           @nvp = %nvp ;
224 0           my @nvpargs = () ;
225 0           push @nvpargs, [ splice @nvp, 0, 2 ] while @nvp ;
226 0   0       map { push @$_, $strings{ $_->[0] } || 0 } @nvpargs ;
  0            
227              
228 0           my $results = $dsn->update( $id, @nvpargs ) ;
229 0           $self->{sql}->{id} = $results->{id} ;
230 0           return $results->{sqlresults} ;
231             }
232              
233             sub combine {
234 0 0   0 0   shift @_ if $_[0] eq __PACKAGE__ ;
235 0           my @records = @_ ;
236 0           my @out = () ;
237              
238 0           while ( @records ) {
239 0           push @out, shift @records ;
240              
241 0 0         last unless @records ;
242 0 0         next unless $records[0]{key} eq 'item' ;
243              
244 0           my @gd = $records[0]{xml}->getdata ;
245 0 0         next unless @gd ;
246 0 0         die if @gd > 1 ;
247            
248 0           $out[-1]{combine} = shift @records ;
249             }
250              
251 0           return @out ;
252             }
253              
254             sub insertall {
255 0 0   0 0   shift @_ if $_[0] eq __PACKAGE__ ;
256 0           my $dsn = shift ;
257 0           my %ids = () ;
258 0           my %refs = () ;
259 0           my %scalars = () ;
260              
261 0           foreach my $self ( @_ ) {
262 0   0       my $pid = $self->parentid || '' ;
263              
264 0 0 0       if ( $self->memory && exists $refs{ $self->memory } ) {
265 0           $self->{key} = $self->reference(
266             $refs{ $self->memory }
267             ) ;
268             }
269 0   0       $self->{key} ||= '' ;
270            
271 0 0 0       $self->{sql}->{refto} ||= $ids{ $self->memory }
      0        
272             || $scalars{ $self->memory }
273             || 0 if $self->memory ;
274              
275 0 0 0       $self->{sql}->{item} = $ids{ $pid } || 0
      0        
      0        
      0        
276             if exists $ids{ $pid }
277             && $self->{key}
278             && $self->{key} ne 'string'
279             && $self->{key} ne 'scalar' ;
280              
281 0 0         if ( $self->{key} eq 'perldata' ) {
282 0           $self->{sql}->{intdata} = 0 ;
283 0           $self->{sql}->{deleted} = 0 ;
284 0           $self->{sql}->{refto} = delete $self->{sql}->{item} ;
285             }
286              
287 0 0         $self->{sql}->{chainedstring} = $ids{string}
288             if exists $self->{sql}->{stringdata} ;
289              
290 0           $self->sql( $dsn ) ;
291            
292 0 0 0       $scalars{ $self->memory } ||= $self->{sql}->{id}
      0        
293             if $self->memory
294             && $self->{key} eq 'scalarref' ;
295 0 0         $ids{string} = undef unless $self->{key} eq 'string' ;
296 0           $ids{ $pid } = $self->{sql}->{id} ;
297 0 0         $refs{ $self->memory } = $self->{sql} if $self->memory ;
298             }
299              
300 0           return $dsn->lastinsertid, \%refs ;
301             }
302              
303             1;
304             __END__