File Coverage

blib/lib/HDB/Object.pm
Criterion Covered Total %
statement 10 13 76.9
branch n/a
condition n/a
subroutine 4 5 80.0
pod n/a
total 14 18 77.7


line stmt bran cond sub pod time code
1             #############################################################################
2             ## This file was generated automatically by Class::HPLOO/0.21
3             ##
4             ## Original file: ./lib/HDB/Object.hploo
5             ## Generation date: 2005-01-23 18:30:36
6             ##
7             ## ** Do not change this file, use the original HPLOO source! **
8             #############################################################################
9            
10             #############################################################################
11             ## Name: Object.pm
12             ## Purpose: HDB::Object - Base class for persistent Class::HPLOO objects.
13             ## Author: Graciliano M. P.
14             ## Modified by:
15             ## Created: 21/09/2004
16             ## RCS-ID:
17             ## Copyright: (c) 2004 Graciliano M. P.
18             ## Licence: This program is free software; you can redistribute it and/or
19             ## modify it under the same terms as Perl itself
20             #############################################################################
21            
22            
23             { package HDB::Object ;
24            
25 1     1   6 use strict qw(vars) ; no warnings ;
  1     1   2  
  1         26  
  1         5  
  1         2  
  1         30  
26            
27 1     1   5 use vars qw(%CLASS_HPLOO @ISA $VERSION) ;
  1         2  
  1         118  
28            
29             $VERSION = '0.02' ;
30            
31             @ISA = qw(Class::HPLOO::Base UNIVERSAL) ;
32            
33 0     0     my $CLASS = 'HDB::Object' ; sub __CLASS__ { 'HDB::Object' } ;
34            
35 1     1   614 use Class::HPLOO::Base ;
  0            
  0            
36            
37             use HDB ;
38            
39             *WITH_HPL = \&HDB::WITH_HPL ;
40             *HPL_MAIN = \&HDB::HPL_MAIN ;
41            
42             my ( %NEW_IDS , %OBJ_TABLE , %OBJ_TABLE_LOADER , $DID_REQUIRED ) ;
43            
44            
45             use overload (
46             'bool' => '_OVER_bool' ,
47             '""' => '_OVER_string' ,
48             'fallback' => 1 ,
49             ) ;
50            
51             sub _OVER_bool { my $this = ref($_[0]) ? shift : undef ;my $CLASS = ref($this) || __PACKAGE__ ; 1 ;}
52            
53             sub _OVER_string {
54             my $this = ref($_[0]) ? shift : undef ;
55             my $CLASS = ref($this) || __PACKAGE__ ;
56            
57             my $class = $this->__CLASS__ ;
58             my $id = $this->__ID__ ;
59            
60             if ( !$id ) {
61             $this->hdb_save ;
62             $id = $this->__ID__ ;
63             }
64            
65             my $ident = "hdbobj__$class\__$id" ;
66             $ident =~ s/::/_/gs ;
67            
68             return $ident ;
69             }
70            
71             sub do_require {
72             my $this = ref($_[0]) ? shift : undef ;
73             my $CLASS = ref($this) || __PACKAGE__ ;
74            
75             return if $DID_REQUIRED ;
76             $DID_REQUIRED = 1 ;
77            
78             my $hpl = &HPL_MAIN() ;
79            
80             if ( $hpl ) {
81             $hpl->use_cached('Hash::NoRef') ;
82             }
83             else {
84             eval(" use Hash::NoRef ") ;
85             }
86            
87             tie( %OBJ_TABLE , 'Hash::NoRef' ) ;
88             }
89            
90             sub RESET {
91             my $this = ref($_[0]) ? shift : undef ;
92             my $CLASS = ref($this) || __PACKAGE__ ;
93            
94             %OBJ_TABLE_LOADER = () ;
95             %OBJ_TABLE = () ;
96             %NEW_IDS = () ;
97             return 1 ;
98             }
99            
100             sub load {
101             my $this = ref($_[0]) ? shift : undef ;
102             my $CLASS = ref($this) || __PACKAGE__ ;
103            
104             $CLASS = $this ? ref $this : shift(@_) ;
105            
106             my @where ;
107            
108             foreach my $i ( @_ ) {
109             if ( $i =~ /^\d+$/s ) { push(@where , "id == $i") ;}
110             else { push(@where , $i) ;}
111             }
112            
113             return if !$CLASS->hdb_table_exists() ;
114            
115             my $hdb_obj = $CLASS->hdb ;
116            
117             my @sel = $hdb_obj->select( $CLASS , (@where ? ['?',@where] : ()) , (!wantarray ? (limit => '1') : () ) , '@%' ) ;
118             return if !@sel ;
119            
120             do_require() ;
121            
122             my @obj ;
123             foreach my $sel_i ( @sel ) {
124             next if !$sel_i ;
125            
126             push(@obj , _build_obj($CLASS , $sel_i , $hdb_obj) ) ;
127             next ;
128            
129             if ( $OBJ_TABLE{"$CLASS/$$sel_i{id}"} ) {
130             delete $OBJ_TABLE_LOADER{"$CLASS/$$sel_i{id}"} ;
131             push(@obj , $OBJ_TABLE{"$CLASS/$$sel_i{id}"} ) ;
132             }
133             else {
134             my $loader ;
135             if ( $OBJ_TABLE_LOADER{"$CLASS/$$sel_i{id}"} ) {
136             $loader = $OBJ_TABLE_LOADER{"$CLASS/$$sel_i{id}"} ;
137             }
138             else {
139             $loader = HDB::Object::Loader::create_loader($CLASS , $sel_i , $hdb_obj) ;
140             $OBJ_TABLE_LOADER{"$CLASS/$$sel_i{id}"} = $loader ;
141             }
142             push(@obj , $loader) ;
143             }
144             }
145            
146             return if !@obj ;
147            
148             return @obj if wantarray ;
149             return $obj[0] ;
150             }
151            
152             sub select {
153             my $this = ref($_[0]) ? shift : undef ;
154             my $CLASS = ref($this) || __PACKAGE__ ;
155            
156             my ( @list , $attr , $id ) ;
157             if ( $#_ == 0 ) { ( $attr ) = @_ ;}
158             elsif ( $#_ == 1 ) { ( $attr , $id ) = @_ ;}
159             elsif ( $#_ > 1 ) { ( $id , @list ) = @_ ;}
160            
161             my $ret ;
162            
163             if ( @list ) {
164             foreach my $list_i ( @list ) {
165             if ( (UNIVERSAL::isa($list_i , 'HDB::Object') && $list_i->{__ID__} == $id) || (ref($list_i) eq 'HDB::Object::Loader' && $list_i->__ID__ == $id) ) {
166             $ret = $list_i ;
167             last ;
168             }
169             }
170             }
171             else {
172             if ( ref( $this->{$attr} ) eq 'ARRAY' ) {
173             foreach my $list_i ( @{ $this->{$attr} } ) {
174             if ( (UNIVERSAL::isa($list_i , 'HDB::Object') && $list_i->{__ID__} == $id) || (ref($list_i) eq 'HDB::Object::Loader' && $list_i->__ID__ == $id) ) {
175             $ret = $list_i ;
176             last ;
177             }
178             }
179             }
180             elsif ( (UNIVERSAL::isa($this->{$attr} , 'HDB::Object') && $this->{$attr}->{__ID__} == $id) || (ref($this->{$attr}) eq 'HDB::Object::Loader' && $this->{$attr}->__ID__ == $id) ) {
181             $ret = $this->{$attr} ;
182             }
183             }
184            
185             return $ret ;
186             }
187            
188             sub _build_obj {
189             my $this = ref($_[0]) ? shift : undef ;
190             my $CLASS = ref($this) || __PACKAGE__ ;
191             my $CLASS = shift(@_) ;
192             my $sel = shift(@_) ;
193             my $hdb_obj = shift(@_) ;
194            
195             my $obj_ident = "$CLASS/$$sel{id}" ;
196            
197             ##print "BUILD OBJ>> $CLASS , $sel , $hdb_obj [$OBJ_TABLE{$obj_ident}]\n" ;
198            
199             return $OBJ_TABLE{$obj_ident} if $OBJ_TABLE{$obj_ident} ;
200            
201             my $this = bless({} , $CLASS) ;
202            
203             $hdb_obj ||= $CLASS->hdb ;
204            
205             &{"$CLASS\::CLASS_HPLOO_TIE_KEYS"}($this) ;
206            
207             foreach my $Key ( keys %$sel ) {
208             if ( $Key =~ /^hdbobj__(\w*?)__(\w+)/ ) {
209             my ( $class_obj , $attr , $id ) = ($1,$2 , $$sel{$Key}) ;
210             $this->{CLASS_HPLOO_ATTR}{$attr} = $this->_build_ref_obj($class_obj,$id) ;
211             }
212             elsif ( $Key =~ /^hdbstore__(\w*?)__(\w+)/ ) {
213             my ( $class_obj , $attr , $freeze ) = ($1,$2 , $$sel{$Key}) ;
214             eval('use Storable qw()') ;
215             if ( !$@ ) {
216             eval {
217             my $thaw = Storable::thaw($freeze) ;
218             $this->{CLASS_HPLOO_ATTR}{$attr} = ref($thaw) eq 'ARRAY' ? $$thaw[0] : undef ;
219             };
220             }
221             }
222             elsif ( exists $this->{CLASS_HPLOO_ATTR}{$Key} ) { $this->{CLASS_HPLOO_ATTR}{$Key} = $$sel{$Key} ;}
223             }
224            
225             $this->{__ID__} = $$sel{id} ;
226             $this->{__HDB_OBJ__} = $hdb_obj ;
227            
228             my @ref_tables = $this->hdb_ref_tables ;
229            
230             foreach my $ref_tables_i ( @ref_tables ) {
231             my ($class_main , $class_obj , $attr) = ( $ref_tables_i =~ /^hdbref__(\w*?)__(\w*?)__(\w+)/ );
232             $class_obj .= '_' if $class_main eq $class_obj ;
233            
234             my @sel = $this->hdb->select( $ref_tables_i , "$class_main == $this->{__ID__}" , cols => "$class_obj" , '@$') ;
235            
236             $this->{CLASS_HPLOO_ATTR}{$attr} = [] ;
237             foreach my $sel_i ( @sel ) {
238             push( @{ $this->{CLASS_HPLOO_ATTR}{$attr} } , $this->_build_ref_obj($class_obj,$sel_i) ) ;
239             }
240             }
241            
242             foreach my $Key ( keys %OBJ_TABLE ) {
243             delete $OBJ_TABLE{$Key} if !defined $OBJ_TABLE{$Key} ;
244             }
245            
246             delete $OBJ_TABLE_LOADER{$obj_ident} ;
247             $OBJ_TABLE{$obj_ident} = $this ;
248            
249             return $this ;
250             }
251            
252             sub hdb_refresh {
253             my $this = ref($_[0]) ? shift : undef ;
254             my $CLASS = ref($this) || __PACKAGE__ ;
255            
256             return if !$this || !$this->{__ID__} ;
257             my $hdb_obj = $this->hdb ;
258             return if !$hdb_obj ;
259            
260             my $sel = $hdb_obj->select( $this->__CLASS__ , "id == $this->{__ID__}" , '$%' ) ;
261            
262             print "REF>> $sel\n" ;
263             }
264            
265             sub _build_ref_obj {
266             my $this = ref($_[0]) ? shift : undef ;
267             my $CLASS = ref($this) || __PACKAGE__ ;
268             my $class_obj = shift(@_) ;
269             my $id = shift(@_) ;
270            
271             $class_obj =~ s/_$// ;
272             $class_obj =~ s/_/::/gs ;
273             if ( UNIVERSAL::isa($class_obj,'HDB::Object') ) {
274             return $class_obj->load($id) ;
275             }
276             return ;
277             }
278            
279             sub __ID__ {
280             my $this = ref($_[0]) ? shift : undef ;
281             my $CLASS = ref($this) || __PACKAGE__ ;
282            
283             return $this->{__ID__} ;
284             }
285            
286             sub hdb_obj_changed {
287             my $this = ref($_[0]) ? shift : undef ;
288             my $CLASS = ref($this) || __PACKAGE__ ;
289            
290             return 1 if ( exists $this->{CLASS_HPLOO_CHANGED} && $this->{CLASS_HPLOO_CHANGED} && ref $this->{CLASS_HPLOO_CHANGED} eq 'HASH' && %{ $this->{CLASS_HPLOO_CHANGED} }) ;
291             return ;
292             }
293            
294             sub hdb {
295             my $this = ref($_[0]) ? shift : undef ;
296             my $CLASS = ref($this) || __PACKAGE__ ;
297            
298             my $dbobj = UNIVERSAL::isa($this , 'HASH') ? $this->{__HDB_OBJ__} : undef ;
299            
300             if ( !$dbobj ) { $dbobj = HDB->HPLOO ;}
301            
302             if ( !$dbobj && WITH_HPL() ) {
303             my $hpl = HPL_MAIN() ;
304             if ( defined $hpl->env->{DOCUMENT_ROOT} ) {
305             my $db_dir = $hpl->env->{DOCUMENT_ROOT} . '/db' ;
306             my $db_file = "$db_dir/hploo.db" ;
307             $dbobj = HDB->new(
308             type => 'sqlite' ,
309             db => $db_file ,
310             ) if -d $db_dir && -w $db_dir && (!-e $db_file || -w $db_file) ;
311             }
312             }
313            
314             if ( !$dbobj ) {
315             warn("Can't find the predefined HPLOO database connection!") ;
316             return ;
317             }
318            
319             if ( UNIVERSAL::isa($this , 'HASH') && !$this->{__HDB_OBJ__} ) {
320             $this->{__HDB_OBJ__} = $dbobj ;
321             }
322            
323             return $dbobj ;
324             }
325            
326             sub hdb_table_exists {
327             my $this = ref($_[0]) ? shift : undef ;
328             my $CLASS = ref($this) || __PACKAGE__ ;
329            
330             $CLASS = $this ? ref $this : shift(@_) ;
331             my $CLASS_HPLOO_HASH = $CLASS->GET_CLASS_HPLOO_HASH ;
332            
333             return 1 if ( (time - $CLASS_HPLOO_HASH->{HDB_TABLE_CHK}) < 2 ) ;
334            
335             my %table_hash = $this ? $this->hdb->tables_hash : $CLASS->hdb->tables_hash ;
336            
337             my $table = $this ? $this->__CLASS__ : $CLASS ;
338             $table = HDB::CMDS::_format_table_name($table) ;
339            
340             if ( $table_hash{$table} ) {
341             $CLASS_HPLOO_HASH->{HDB_TABLE_CHK} = time ;
342             return 1 ;
343             }
344             $CLASS_HPLOO_HASH->{HDB_TABLE_CHK} = undef ;
345            
346             return ;
347             }
348            
349             sub hdb_create_table {
350             my $this = ref($_[0]) ? shift : undef ;
351             my $CLASS = ref($this) || __PACKAGE__ ;
352            
353             my $class_hploo = $this->GET_CLASS_HPLOO_HASH ;
354             my $CLASS = $this->__CLASS__ ;
355            
356             if ( $CLASS !~ /^\w+(?:::\w+)*$/ ) {
357             warn("Can't use class name '$CLASS' as a table name!!!\n") ;
358             }
359            
360             $CLASS =~ s/:+/_/gs ;
361            
362             my @cols ;
363             foreach my $order_i ( @{$class_hploo->{ATTR_ORDER}} ) {
364             my $tp = $class_hploo->{ATTR}{$order_i}{tp} ;
365            
366             my ( $col_name , $tp , $table_ref , @cols_ref ) = $this->_hdb_attr_type($order_i , $tp) ;
367            
368             if ( $table_ref ) {
369             $this->hdb->create( $table_ref , @cols_ref ) ;
370             #print $this->hdb->sql . "\n" ;
371             }
372             else {
373             push(@cols , $col_name , $this->_hdb_col_type_hploo_2_hdb($tp) ) ;
374             }
375             }
376            
377             warn("Can't store in the DB class $CLASS since the class doesn't have attributes!") if !@cols ;
378            
379             $this->hdb->create( $CLASS , @cols ) ;
380             #print $this->hdb->sql . "\n" ;
381             }
382            
383             sub hdb_ref_tables {
384             my $this = ref($_[0]) ? shift : undef ;
385             my $CLASS = ref($this) || __PACKAGE__ ;
386            
387             my $CLASS = $this ? $this->__CLASS__ : shift(@_) ;
388             my @tables = $this ? $this->hdb->tables : $CLASS->hdb->tables ;
389            
390             $CLASS =~ s/:+/_/gs ;
391             my @ref ;
392             foreach my $tables_i ( @tables ) {
393             push(@ref , $tables_i) if $tables_i =~ /hdbref__$CLASS\__/ ;
394             }
395            
396             return @ref ;
397             }
398            
399             sub hdb_ref_to_me_tables {
400             my $this = ref($_[0]) ? shift : undef ;
401             my $CLASS = ref($this) || __PACKAGE__ ;
402            
403             my $CLASS = $this ? $this->__CLASS__ : shift(@_) ;
404             my @tables = $this ? $this->hdb->tables : $CLASS->hdb->tables ;
405            
406             $CLASS =~ s/:+/_/gs ;
407             my @ref ;
408             foreach my $tables_i ( @tables ) {
409             push(@ref , $tables_i) if $tables_i =~ /hdbref__(\w+?)__$CLASS\__/ ;
410             }
411            
412             return @ref ;
413             }
414            
415             sub hdb_referenced_ids {
416             my $this = ref($_[0]) ? shift : undef ;
417             my $CLASS = ref($this) || __PACKAGE__ ;
418            
419             my $CLASS = $this ? $this->__CLASS__ : shift(@_) ;
420             my $this_or_class = $this || $CLASS ;
421            
422             my $hdb_obj = shift(@_) || $this_or_class->hdb ;
423            
424             my $class_obj = $CLASS ;
425             $class_obj =~ s/:+/_/gs ;
426            
427             my $can_have_ref ;
428            
429             my @ref_tables = $this_or_class->hdb_ref_to_me_tables ;
430            
431             $can_have_ref = 1 if @ref_tables ;
432            
433             my %ids_ok ;
434            
435             foreach my $ref_tables_i ( @ref_tables ) {
436             my @sel = $hdb_obj->select( $ref_tables_i , cols => "$class_obj" , '@$') ;
437             @ids_ok{@sel} = (1) x @sel ;
438             }
439            
440             foreach my $tables_i ( $hdb_obj->tables ) {
441             foreach my $cols_i ( $hdb_obj->names($class_obj) ) {
442             if ( $cols_i =~ /^hdbobj__$class_obj\__/ ) {
443             my @sel = $hdb_obj->select( $tables_i , cols => $cols_i , '@$') ;
444             @ids_ok{@sel} = (1) x @sel ;
445             $can_have_ref = 1 ;
446             }
447             }
448             }
449            
450             return \%ids_ok if $can_have_ref ;
451             return ;
452             }
453            
454             sub hdb_clean_unref {
455             my $this = ref($_[0]) ? shift : undef ;
456             my $CLASS = ref($this) || __PACKAGE__ ;
457            
458             my $CLASS = $this ? $this->__CLASS__ : shift(@_) ;
459             my $this_or_class = $this || $CLASS ;
460            
461             my $hdb_obj = shift(@_) || $this_or_class->hdb ;
462            
463             my $class_obj = $CLASS ;
464             $class_obj =~ s/:+/_/gs ;
465            
466             my $ids_ok = $this_or_class->hdb_referenced_ids($hdb_obj) ;
467            
468             $hdb_obj->delete( $class_obj , ["id != ?", ['AND'] , keys %$ids_ok]) if $ids_ok ;
469             }
470            
471             sub _hdb_attr_type {
472             my $this = ref($_[0]) ? shift : undef ;
473             my $CLASS = ref($this) || __PACKAGE__ ;
474             my $attr = shift(@_) ;
475             my $tp = shift(@_) ;
476            
477             my $CLASS = $this->__CLASS__ ;
478            
479             $CLASS =~ s/:+/_/gs ;
480            
481             my ( $tp1 ,$tp2 ) ;
482            
483             if ( $tp =~ /(?:ref\s*)?(array\s*|hash\s*)?(&\w+|\w+(?:::\w+)*)/ ) { ( $tp1 ,$tp2 ) = ($1,$2) ;}
484             else { $tp2 = $tp ;}
485            
486             my $is_hdbobj = UNIVERSAL::isa($tp2 , 'HDB::Object') ;
487            
488             $tp2 =~ s/:+/_/gs ;
489             $tp = $tp2 ;
490            
491             my $is_obj = ($tp =~ /^(?:boolean|integer|floating|string|sub_\w+|any|&\w+)$/ ) ? 0 : 1 ;
492            
493             my $col_name ;
494            
495             if ( !$is_hdbobj && $is_obj ) {
496             return( "hdbstore__$tp2\__$attr" , '*' ) ;
497             }
498             elsif ( $is_obj ) {
499             $col_name = "hdbobj__$tp2\__$attr" ;
500             $tp = 'integer' ;
501             }
502             else { $col_name = $attr ;}
503            
504             my ($table_ref , @cols_ref) ;
505             if ( $tp1 eq 'array' ) {
506             $table_ref = "hdbref__$CLASS\__$tp2\__$attr" ;
507             $tp2 .= '_' if $CLASS eq $tp2 ;
508             @cols_ref = (
509             $CLASS => 'integer' ,
510             $tp2 => 'integer' ,
511             ) ;
512             }
513            
514             return( $col_name , $tp , $table_ref , @cols_ref ) ;
515             }
516            
517             sub _hdb_col_type_hploo_2_hdb {
518             my $this = ref($_[0]) ? shift : undef ;
519             my $CLASS = ref($this) || __PACKAGE__ ;
520             my $hploo_type = shift(@_) ;
521            
522             if ( $hploo_type =~ /(?:any|string)/i ) { return '*' ;}
523             elsif ( $hploo_type =~ /bool/i ) { return 'boolean' ;}
524             elsif ( $hploo_type =~ /int/i ) { return 'int' ;}
525             elsif ( $hploo_type =~ /float/i ) { return 'float' ;}
526             else { return '*' ;}
527             }
528            
529             sub hdb_max_id {
530             my $this = ref($_[0]) ? shift : undef ;
531             my $CLASS = ref($this) || __PACKAGE__ ;
532            
533             my $max_id = $this->hdb->select( $this->__CLASS__ , cols => '>id' , '$' ) ;
534             return $max_id ;
535             }
536            
537             sub hdb_delete {
538             my $this = ref($_[0]) ? shift : undef ;
539             my $CLASS = ref($this) || __PACKAGE__ ;
540            
541             return if !$this->hdb_table_exists ;
542             my $id = $this->{__ID__} ;
543            
544             return if ( $id eq '' || !$this->hdb->select( $this->__CLASS__ , "id == $id" , cols => 'id' , '$' ) ) ;
545            
546             $this->hdb->delete( $this->__CLASS__ , "id == $id" ) ;
547            
548             %$this = () ;
549            
550             return 1 ;
551             }
552            
553             sub hdb_new_id {
554             my $this = ref($_[0]) ? shift : undef ;
555             my $CLASS = ref($this) || __PACKAGE__ ;
556            
557             my $id = $this->hdb_max_id + 1 ;
558             my $class = $this->__CLASS__ ;
559             while( $NEW_IDS{$class}{$id} ) { ++$id ;}
560             $NEW_IDS{$class}{$id} = 1 ;
561             return $id ;
562             }
563            
564             sub hdb_save {
565             my $this = ref($_[0]) ? shift : undef ;
566             my $CLASS = ref($this) || __PACKAGE__ ;
567             my %args = @_ ;
568             @_ = () ;
569            
570             $this->hdb_create_table if !$this->hdb_table_exists ;
571            
572             return if !$args{save_all} && !$this->hdb_obj_changed ;
573            
574             my $class_hploo = $this->GET_CLASS_HPLOO_HASH ;
575            
576             my $class_hploo_changed = $this->{CLASS_HPLOO_CHANGED} ;
577             $this->{CLASS_HPLOO_CHANGED} = undef ;
578            
579             my $id = $this->{__ID__} ;
580             my $insert ;
581            
582             if ( $id eq '' || ($id && !$this->hdb->select( $this->__CLASS__ , "id == $id" , cols => 'id' , '$' )) ) {
583             $id = $this->hdb_new_id ;
584             $insert = 1 ;
585             }
586            
587             my @del_attr_keys ;
588            
589             my $saved_classes = $args{saved_classes} || {} ;
590            
591             foreach my $order_i ( @{$class_hploo->{ATTR_ORDER}} ) {
592             my $tp = $class_hploo->{ATTR}{$order_i}{tp} ;
593             my ( $col_name , $tp , $table_ref , @cols_ref ) = $this->_hdb_attr_type($order_i , $tp) ;
594            
595             ##print ">> $col_name , $tp , $table_ref , @cols_ref \n" ;
596            
597             if ( $table_ref ) {
598             if ( ref $this->{$order_i} eq 'ARRAY' ) {
599             my (@ids , %ids , $c) ;
600            
601             foreach my $attr_i ( @{$this->{$order_i}} ) {
602             if ( ref($attr_i) eq 'HDB::Object::Loader' ) {
603             my $id = $attr_i->[1]{id} ;
604             push(@ids , $id) ;
605             $ids{$id} = ++$c ;
606             }
607             elsif ( UNIVERSAL::isa($attr_i , 'HDB::Object') ) {
608             $attr_i->hdb_save( no_auto_clean_unref => 1 , saved_classes => $saved_classes ) ;
609             $$saved_classes{ $attr_i->__CLASS__ } = 1 ;
610             push(@ids , $attr_i->{__ID__}) ;
611             $ids{$attr_i->{__ID__}} = ++$c ;
612             }
613             }
614            
615             my @sel = $this->hdb->select( $table_ref , "$cols_ref[0] == $id" , cols => "$cols_ref[2],id" , '@@') ;
616            
617             my (@del_ids , %sel_ids , %sel_pos ) ;
618            
619             #print "IDS[$this]>> @ids\n" ;
620            
621             $c = 0 ;
622             foreach my $sel_i ( @sel ) {
623             $sel_ids{$$sel_i[0]} = ++$c ;
624             $sel_pos{$c} = $$sel_i[1] ;
625             push(@del_ids , $$sel_i[1]) if $ids{$$sel_i[0]} != $c ;
626             #print "SEL>> $$sel_i[0] , $$sel_i[1] [$c] >> $ids{$$sel_i[0]}\n" ;
627             }
628            
629             my @dels = @del_ids[($#ids+1)..$#del_ids] ;
630             #print "DEL>> @dels\n" ;
631            
632             $this->hdb->delete( $table_ref , ["$cols_ref[2] == ?" , @dels] ) if @dels ;
633             #print $this->hdb->sql . "\n" if @dels ;
634            
635             foreach my $ids_i ( @ids ) {
636             if ( $ids{$ids_i} != $sel_ids{$ids_i} ) {
637             my $pos = $sel_pos{ $ids{$ids_i} } ;
638             if ( $pos ) {
639             $this->hdb->update( $table_ref , "id == $pos" , {$cols_ref[0] => $id , $cols_ref[2] => $ids_i}) ;
640             #print $this->hdb->sql . "\n" ;
641             }
642             else {
643             $this->hdb->insert( $table_ref , {$cols_ref[0] => $id , $cols_ref[2] => $ids_i}) ;
644             #print $this->hdb->sql . "\n" ;
645             }
646             }
647             }
648            
649             }
650             elsif ( UNIVERSAL::isa($this->{$order_i} , 'HDB::Object') ) {
651             $this->{$order_i}->hdb_save( no_auto_clean_unref => 1 , , saved_classes => $saved_classes ) ;
652             $$saved_classes{ $this->{$order_i}->__CLASS__ } = 1 ;
653             }
654             }
655             elsif ( $col_name =~ /^hdbobj/ ) {
656             if ( ref($this->{$order_i}) eq 'HDB::Object::Loader' ) {
657             my $id = $this->{$order_i}->[1]{id} ;
658             $this->{CLASS_HPLOO_ATTR}{$col_name} = $id ;
659             }
660             elsif ( UNIVERSAL::isa($this->{$order_i} , 'HDB::Object') ) {
661             $this->{$order_i}->hdb_save( no_auto_clean_unref => 1 , saved_classes => $saved_classes , save_all => $args{save_all} ) ;
662             $$saved_classes{ $this->{$order_i}->__CLASS__ } = 1 ;
663             $this->{CLASS_HPLOO_ATTR}{$col_name} = $this->{$order_i}->{__ID__} ;
664             }
665             push(@del_attr_keys , $col_name) ;
666             }
667             elsif ( $col_name =~ /^hdbstore/ ) {
668             eval('use Storable qw()') ;
669             if ( !$@ ) {
670             eval {
671             $this->{CLASS_HPLOO_ATTR}{$col_name} = Storable::freeze( [$this->{$order_i}] ) ;
672             };
673             push(@del_attr_keys , $col_name) ;
674             }
675             }
676             }
677            
678             my $ret ;
679             if ( $insert ) {
680             $this->{CLASS_HPLOO_ATTR}{id} = $this->{__ID__} = $id ;
681             push(@del_attr_keys , 'id') ;
682             $ret = $this->hdb->insert( $this->__CLASS__ , $this->{CLASS_HPLOO_ATTR} ) ;
683             }
684             else {
685             my %changeds ;
686             if ( $args{save_all} ) { %changeds = %{ $this->{CLASS_HPLOO_ATTR} } ;}
687             else {
688             foreach my $Key ( keys %$class_hploo_changed ) {
689             $changeds{$Key} = $this->{CLASS_HPLOO_ATTR}{$Key} ;
690             }
691             }
692            
693             $ret = $this->hdb->update( $this->__CLASS__ , "id == $id" , \%changeds ) ;
694             }
695            
696             foreach my $del_keys_i ( @del_attr_keys ) { delete $this->{CLASS_HPLOO_ATTR}{$del_keys_i} ;}
697            
698             $$saved_classes{ $this->__CLASS__ } = 1 ;
699            
700             if ( !$args{no_auto_clean_unref} ) {
701             foreach my $Key ( keys %$saved_classes ) {
702             if ( defined &{ $Key . '::AUTO_CLEAN_UNREF'} && &{ $Key . '::AUTO_CLEAN_UNREF'}() && (time - $class_hploo->{HDB_TABLE_AUTOCLS}{$Key}) > 2 ) {
703             $Key->hdb_clean_unref( $this->hdb ) ;
704             $class_hploo->{HDB_TABLE_AUTOCLS}{$Key} = time ;
705             }
706             }
707             }
708            
709             return $ret ;
710             }
711            
712             sub hdb_dump_table {
713             my $this = ref($_[0]) ? shift : undef ;
714             my $CLASS = ref($this) || __PACKAGE__ ;
715             my $table = shift(@_) ;
716            
717             if ( !$this ) {
718             $this = $table || $_[0] ;
719             $table = $_[0] if $_[0] ;
720             }
721            
722             return '' if !$this->hdb_table_exists ;
723             return $this->hdb->dump_table($table) ;
724             }
725            
726             sub STORABLE_freeze {
727             my $this = ref($_[0]) ? shift : undef ;
728             my $CLASS = ref($this) || __PACKAGE__ ;
729             my $cloning = shift(@_) ;
730            
731             return(
732             $this ,
733             {
734             (ref $this->{CLASS_HPLOO_ATTR} eq 'HASH' ? %{$this->{CLASS_HPLOO_ATTR}} : ()) ,
735             id => $this->{__ID__} ,
736             }
737             ) ;
738             }
739            
740             sub STORABLE_thaw {
741             my $this = ref($_[0]) ? shift : undef ;
742             my $CLASS = ref($this) || __PACKAGE__ ;
743             my $cloning = shift(@_) ;
744             my $serial = shift(@_) ;
745             my $attrs = shift(@_) ;
746            
747             my $class = ref $this ;
748            
749             $this->{__ID__} = delete $attrs->{id} ;
750            
751             $this->{CLASS_HPLOO_ATTR} = {} ;
752             %{ $this->{CLASS_HPLOO_ATTR} } = %$attrs ;
753            
754             &{"$class\::CLASS_HPLOO_TIE_KEYS"}($this) ;
755            
756             $this->hdb ;
757             return ;
758             }
759            
760             sub DESTROY {
761             my $this = ref($_[0]) ? shift : undef ;
762             my $CLASS = ref($this) || __PACKAGE__ ;
763            
764             return if !%$this ;
765             $this->hdb_save ;
766             }
767            
768            
769            
770             }
771            
772            
773             ################################################################################
774            
775             { package HDB::Object::Loader ;
776            
777             use strict qw(vars) ;
778            
779             use vars qw($AUTOLOAD) ;
780            
781             use overload (
782             'bool' => \&HDB::Object::_OVER_bool ,
783             '""' => \&HDB::Object::_OVER_string ,
784             '%{}' => '_OVER_hash' ,
785             'fallback' => 1 ,
786             );
787            
788             sub _OVER_hash {
789             _build($_[0]) ; return $_[0] ;
790            
791             if ( !$_[0][3] ) {
792             my %hash = (1) ;
793             $_[0][3] = \%hash ;
794             $_[0][4] = tie( %hash , 'HDB::Object::Loader::TieHandler' , @{$_[0]}[0..2] ) ;
795             }
796            
797             if ( $_[0][4] && $_[0][4]->[3] ) {
798             $_[0] = $_[0][4]->[3] ;
799             return $_[0] ;
800             }
801            
802             return $_[0][3] ;
803             }
804            
805             sub create_loader { bless [ @_ ] ;}
806            
807             sub _build {
808             my @args = @{$_[0]} ;
809             $_[0] = HDB::Object::_build_obj(@args) ;
810            
811             die "INTERNAL ERROR: Cannot build instance of '$args[0]'\n" unless defined $_[0] ;
812             # This can occur if the class wasn't loaded correctly.
813             die "INTERNAL ERROR: _build() failed to build a new object\n" if ref($_[0]) eq __PACKAGE__;
814            
815             return $_[0] ;
816             }
817            
818             sub __CLASS__ {
819             return $_[0][0] ;
820             }
821            
822             sub __ID__ {
823             return $_[0][1]{id} ;
824             }
825            
826             sub can {
827             _build($_[0]);
828             $_[0]->can($_[1]);
829             }
830            
831             sub isa {
832             $_[0][0]->isa($_[1]) ;
833             }
834            
835             sub AUTOLOAD {
836             my ($subname) = $AUTOLOAD =~ /([^:]+)$/ ;
837            
838             my $realclass = $_[0][0] ;
839             _build( $_[0] ) ;
840            
841             my $func = $_[0]->can( $subname );
842            
843             die "Cannot call '$subname' on an instance of '$realclass'\n" unless ref( $func ) eq 'CODE';
844            
845             goto &$func ;
846             }
847            
848             ## Don't need to save if we haven't changed attributes:
849             sub DESTROY {
850             ##_build($_[0]);
851             ##$_[0]->DESTROY(@_[1..$#_]);
852             }
853            
854             }
855            
856             ################################################################################
857            
858             { package HDB::Object::Loader::TieHandler ;
859            
860             use strict qw(vars) ;
861             no warnings ;
862            
863             sub TIEHASH { shift ; bless [ @_ ] ;}
864            
865             my $val ;
866            
867             sub FETCH { #print STDOUT "FETCH>> @_\n" ;
868             my $this = shift ;
869             my $key = shift ;
870            
871             return $this->[1]{id} if $key eq '__ID__' ;
872            
873             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
874            
875             return $this->[3]{$key} ;
876             }
877            
878             sub STORE { #print STDOUT "STORE>> @_\n" ;
879             my $this = shift ;
880             my $key = shift ;
881            
882             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
883            
884             return $this->[3]{$key} ;
885             }
886            
887             sub DELETE { #print STDOUT "DELETE>> @_\n" ;
888             my $this = shift ;
889             my $key = shift ;
890            
891             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
892            
893             return delete $this->[3]{$key} ;
894             }
895            
896             sub EXISTS { #print STDOUT "EXISTS>> @_\n" ;
897             my $this = shift ;
898             my $key = shift ;
899            
900             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
901            
902             return exists $this->[3]{$key} ;
903             }
904            
905             sub FIRSTKEY { #print STDOUT "FIRSTKEY>> @_\n" ;
906             my $this = shift ;
907            
908             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
909            
910             return (keys %{$this->[3]})[0] ;
911             }
912            
913             sub NEXTKEY { #print STDOUT "NEXTKEY>> @_\n" ;
914             my $this = shift ;
915             my $keylast = shift ;
916            
917             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
918            
919             my $ret_next ;
920             foreach my $keys_i ( keys %{$this->[3]} ) {
921             if ($ret_next) { return $keys_i ;}
922             if ($keys_i eq $keylast || !defined $keylast) { $ret_next = 1 ;}
923             }
924            
925             return undef ;
926             }
927            
928             sub CLEAR { #print STDOUT "CLEAR>> @_\n" ;
929             my $this = shift ;
930            
931             $this->[3] = HDB::Object::_build_obj( @{$this}[0..2] ) if !defined $this->[3] ;
932             %{$this->[3]} = () ;
933            
934             return ;
935             }
936            
937             sub UNTIE {}
938             sub DESTROY {}
939            
940             }
941            
942             1 ;
943            
944            
945             __END__