File Coverage

blib/lib/LittleORM/Model.pm
Criterion Covered Total %
statement 36 835 4.3
branch 0 316 0.0
condition 0 130 0.0
subroutine 12 72 16.6
pod 0 19 0.0
total 48 1372 3.5


line stmt bran cond sub pod time code
1 1     1   6251 use strict;
  1         2  
  1         40  
2              
3 1     1   368 use LittleORM::Db ();
  1         2  
  1         20  
4 1     1   379 use LittleORM::Db::Field ();
  1         2  
  1         16  
5 1     1   288 use LittleORM::Meta::LittleORMHasDbh ();
  1         1  
  1         29  
6              
7             package LittleORM::Model;
8              
9 1     1   6 use Moose -traits => 'LittleORMHasDbh';
  1         2  
  1         4  
10 1     1   4321 use Moose::Util::TypeConstraints;
  1         1  
  1         8  
11              
12             has '_rec' => ( is => 'rw', isa => 'HashRef', required => 1, metaclass => 'LittleORM::Meta::Attribute', description => { ignore => 1 } );
13              
14 1     1   1802 use Carp::Assert 'assert';
  1         1  
  1         6  
15 1     1   113 use Scalar::Util 'blessed';
  1         2  
  1         58  
16 1     1   8272 use Module::Load ();
  1         762  
  1         29  
17 1     1   398 use LittleORM::Model::Field ();
  1         4  
  1         28  
18 1     1   378 use LittleORM::Model::Value ();
  1         3  
  1         27  
19 1     1   400 use LittleORM::Model::Dbh ();
  1         3  
  1         6321  
20              
21 0     0     sub _db_table{ assert( 0, '" _db_table " method must be redefined.' ) }
22              
23             # Let it be separate method, m'kay?
24             sub _clear
25             {
26 0     0     my $self = shift;
27              
28 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
29             {
30 0 0         next if &__descr_attr( $attr, 'do_not_clear_on_reload' ); # well, kinda crutch...
31             # - Kain
32              
33 0 0         if( $attr -> has_clearer() )
34             {
35              
36             # http://search.cpan.org/~doy/Moose-2.0603/lib/Class/MOP/Attribute.pm
37             # $attr->clearer
38             # The accessor, reader, writer, predicate, and clearer methods all
39             # return exactly what was passed to the constructor, so it can be
40             # either a string containing a method name, or a hash reference.
41              
42             # -- why does it have to be so complex?
43            
44 0           my $clearer = $attr -> clearer();
45              
46             # ok, as doc above says:
47 0 0         if( ref( $clearer ) )
48             {
49 0           my $code = ${ [ values %{ $clearer } ] }[ 0 ];
  0            
  0            
50 0           $code -> ( $self );
51              
52             } else
53             {
54 0           $self -> $clearer();
55             }
56            
57             } else
58             {
59 0           $attr -> clear_value( $self );
60             }
61             }
62              
63 0           return 1;
64             }
65              
66             sub __for_read
67             {
68 0     0     return ( _for_what => 'read' );
69             }
70              
71             sub __for_write
72             {
73 0     0     return ( _for_what => 'write' );
74             }
75              
76             sub reload
77             {
78 0     0 0   my $self = shift;
79              
80 0 0         if( my @pk = $self -> __find_primary_keys() )
81             {
82 0           my %get_args = ();
83              
84 0           foreach my $pk ( @pk )
85             {
86 0           my $pkname = $pk -> name();
87 0           $get_args{ $pkname } = $self -> $pkname();
88             }
89              
90 0           $self -> _clear();
91              
92 0           my $sql = $self -> __form_get_sql( %get_args,
93             _limit => 1 );
94              
95 0           my $rec = &LittleORM::Db::getrow( $sql, $self -> __get_dbh( &__for_read() ) );
96 0           $self -> _rec( $rec );
97              
98             } else
99             {
100 0           assert( 0, 'reload in only supported for models with PK' );
101             }
102             }
103              
104             sub clone
105             {
106 0     0 0   my $self = shift;
107              
108 0           my $class = ref( $self );
109              
110 0           return $class -> new( _rec => $self -> _rec() );
111             }
112              
113             sub get
114             {
115 0     0 0   my $self = shift;
116              
117 0           my @args = @_;
118 0           my %args = @args;
119              
120 0           my $sql = $self -> __form_get_sql( @args, _limit => 1 );
121              
122 0 0         if( $args{ '_debug' } )
123             {
124 0           return $sql;
125             }
126              
127 0           my $rec = &LittleORM::Db::getrow( $sql, $self -> __get_dbh( @args,
128             &__for_read() ) );
129              
130 0           my $rv = undef;
131              
132 0 0         if( $rec )
133             {
134 0           $rv = $self -> create_one_return_value_item( $rec, @args );
135             }
136              
137 0           return $rv;
138             }
139              
140             sub borrow_field
141             {
142 0     0 0   my $self = shift;
143 0           my $attrname = shift;
144 0           my %more = @_;
145              
146 0 0         if( $attrname )
147             {
148 0 0         unless( exists $more{ 'db_field_type' } )
149             {
150 0           my $attr = $self -> meta() -> find_attribute_by_name( $attrname );
151 0 0         if( my $t = &__descr_attr( $attr, 'db_field_type' ) )
152             {
153 0           $more{ 'db_field_type' } = $t;
154             }
155             }
156             }
157              
158 0   0       my $rv = LittleORM::Model::Field -> new( model => ( ref( $self ) or $self ),
159             %more );
160 0 0         if( $attrname )
161             {
162 0           assert( my $attr = $self -> meta() -> find_attribute_by_name( $attrname ) );
163 0           $rv -> base_attr( $attrname );
164             }
165              
166 0           return $rv;
167             }
168              
169             sub create_one_return_value_item
170             {
171 0     0 0   my $self = shift;
172 0           my $rec = shift;
173 0           my %args = @_;
174              
175 0           my $rv = undef;
176              
177 0 0         if( $rec )
178             {
179 0 0 0       if( $args{ '_fieldset' } or $args{ '_groupby' } )
180             {
181 0           $rv = LittleORM::DataSet -> new();
182              
183 0 0         if( my $fs = $args{ '_fieldset' } )
184             {
185 0           foreach my $f ( @{ $fs } )
  0            
186             {
187 0 0         unless( LittleORM::Model::Field -> this_is_field( $f ) )
188             {
189 0           $f = $self -> borrow_field( $f,
190             select_as => &__get_db_field_name( $self -> meta() -> find_attribute_by_name( $f ) ) );
191             }
192              
193 0           my $dbfield = $f -> select_as();
194 0           my $value = $f -> post_process() -> ( $rec -> { $dbfield } );
195              
196 0           $rv -> add_to_set( { model => $f -> model(),
197             base_attr => $f -> base_attr(),
198             orm_coerce => $f -> orm_coerce(),
199             dbfield => $dbfield,
200             value => $value } );
201             }
202             }
203              
204 0 0         if( my $grpby = $args{ '_groupby' } )
205             {
206 0           foreach my $f ( @{ $grpby } )
  0            
207             {
208 0   0       my ( $dbfield,
209             $post_process,
210             $base_attr,
211             $orm_coerce,
212             $model ) = ( undef,
213             undef,
214             undef,
215             1,
216             ( ref( $self ) or $self ) );
217              
218 0 0         if( LittleORM::Model::Field -> this_is_field( $f ) )
219             {
220 0           $dbfield = $f -> select_as();
221 0           $base_attr = $f -> base_attr();
222 0           $post_process = $f -> post_process();
223 0           $model = $f -> model();
224 0           $orm_coerce = $f -> orm_coerce();
225              
226             } else
227             {
228 0           $dbfield = &__get_db_field_name( $self -> meta() -> find_attribute_by_name( $f ) );
229             }
230              
231 0 0         my $value = ( $post_process ? $post_process -> ( $rec -> { $dbfield } ) : $rec -> { $dbfield } );
232 0           $rv -> add_to_set( { model => $model,
233             base_attr => $base_attr,
234             dbfield => $dbfield,
235             orm_coerce => $orm_coerce,
236             value => $value } );
237             }
238             }
239             } else
240             {
241 0           $rv = $self -> new( _rec => $rec );
242             }
243             }
244 0           return $rv;
245             }
246              
247             sub values_list
248             {
249 0     0 0   my ( $self, $fields, $args ) = @_;
250              
251             # example: @values = Class -> values_list( [ 'id', 'name' ], [ something => { '>', 100 } ] );
252             # will return ( [ id, name ], [ id1, name1 ], ... )
253              
254 0           my @rv = ();
255              
256 0           foreach my $o ( $self -> get_many( @{ $args } ) )
  0            
257             {
258 0           my @l = map { $o -> $_() } @{ $fields };
  0            
  0            
259              
260 0           push @rv, \@l;
261             }
262              
263 0           return @rv;
264             }
265              
266             sub get_or_create
267             {
268 0     0 0   my $self = shift;
269              
270 0           my $r = $self -> get( @_ );
271              
272 0 0         unless( $r )
273             {
274 0           $r = $self -> create( @_ );
275             }
276              
277 0           return $r;
278             }
279              
280             sub get_many
281             {
282 0     0 0   my $self = shift;
283 0           my @args = @_;
284 0           my %args = @args;
285 0           my @outcome = ();
286              
287 0           my $sql = $self -> __form_get_sql( @args );
288              
289 0 0         if( $args{ '_debug' } )
290             {
291 0           return $sql;
292             }
293              
294 0           my $sth = &LittleORM::Db::prep( $sql, $self -> __get_dbh( @args,
295             &__for_read() ) );
296 0           $sth -> execute();
297              
298 0           while( my $data = $sth -> fetchrow_hashref() )
299             {
300 0           my $o = $self -> create_one_return_value_item( $data, @args );
301 0           push @outcome, $o;
302             }
303              
304 0           $sth -> finish();
305              
306 0           return @outcome;
307             }
308              
309             sub _sql_func_on_attr
310             {
311 0     0     my $self = shift;
312 0           my $func = shift;
313 0           my $attr = shift;
314              
315 0           my @args = @_;
316 0           my %args = @args;
317              
318 0           my $outcome = 0;
319              
320 0           my $sql = $self -> __form_sql_func_sql( _func => $func,
321             _attr => $attr,
322             @args );
323 0 0         if( $args{ '_debug' } )
324             {
325 0           return $sql;
326             }
327              
328 0           my $sth = &LittleORM::Db::prep( $sql, $self -> __get_dbh( @args,
329             &__for_read() ) );
330 0           $sth -> execute();
331 0           my $rows = $sth -> rows();
332            
333 0 0         if( $args{ '_groupby' } )
    0          
334             {
335 0           $outcome = [];
336              
337 0           while( my $data = $sth -> fetchrow_hashref() )
338             {
339 0           my $set = LittleORM::DataSet -> new();
340 0           while( my ( $k, $v ) = each %{ $data } )
  0            
341             {
342 0   0       my $field = { model => ( ref( $self ) or $self ),
343             dbfield => $k,
344             orm_coerce => 1,
345             value => $v };
346              
347 0           $set -> add_to_set( $field );
348             }
349 0           push @{ $outcome }, $set;
  0            
350             }
351              
352             } elsif( $rows == 1 )
353             {
354 0           $outcome = $sth -> fetchrow_hashref() -> { $func };
355              
356             } else
357             {
358 0           assert( 0,
359             sprintf( "Got '%s' for '%s'",
360             $rows,
361             $sql ) );
362             }
363              
364 0           $sth -> finish();
365              
366 0           return $outcome;
367             }
368              
369             sub max
370             {
371 0     0 0   my $self = shift;
372              
373 0           assert( my $attrname = $_[ 0 ] );
374              
375 0           my $rv = $self -> _sql_func_on_attr( 'max', @_ );
376              
377 0           my $attr = undef;
378              
379 0 0         if( LittleORM::Model::Field -> this_is_field( $attrname ) )
380             {
381 0           assert( $attr = $self -> meta() -> find_attribute_by_name( $attrname -> base_attr() ) );
382             } else
383             {
384 0           assert( $attr = $self -> meta() -> find_attribute_by_name( $attrname ) );
385             }
386              
387 0 0         if( my $coerce_from = &__descr_attr( $attr, 'coerce_from' ) )
388             {
389 0           $rv = $coerce_from -> ( $rv );
390             }
391              
392 0           return $rv;
393             }
394              
395              
396             sub min
397             {
398 0     0 0   my $self = shift;
399              
400 0           assert( my $attrname = $_[ 0 ] );
401              
402 0           my $rv = $self -> _sql_func_on_attr( 'min', @_ );
403              
404 0           my $attr = undef;
405              
406 0 0         if( LittleORM::Model::Field -> this_is_field( $attrname ) )
407             {
408 0           assert( $attr = $self -> meta() -> find_attribute_by_name( $attrname -> base_attr() ) );
409             } else
410             {
411 0           assert( $attr = $self -> meta() -> find_attribute_by_name( $attrname ) );
412             }
413              
414 0 0         if( my $coerce_from = &__descr_attr( $attr, 'coerce_from' ) )
415             {
416 0           $rv = $coerce_from -> ( $rv );
417             }
418              
419 0           return $rv;
420             }
421              
422              
423             # sub min
424             # {
425             # my $self = shift;
426              
427             # assert( my $attrname = $_[ 0 ] );
428              
429             # my $rv = $self -> _sql_func_on_attr( 'min', @_ );
430              
431             # assert( my $attr = $self -> meta() -> find_attribute_by_name( $attrname ) );
432              
433             # if( my $coerce_from = &__descr_attr( $attr, 'coerce_from' ) )
434             # {
435             # $rv = $coerce_from -> ( $rv );
436             # }
437              
438             # return $rv;
439             # }
440              
441             sub __default_db_field_name_for_func
442             {
443 0     0     my ( $self, %args ) = @_;
444              
445 0           my $rv = '';
446 0           assert( my $func = $args{ '_func' } );
447              
448 0 0         if( $func eq 'count' )
449             {
450 0           $rv = '*';
451 0 0         if( my $d = $args{ '_distinct' } )
452             {
453 0           my @distinct_on = $self -> __get_distinct_on_attrs( $d );
454              
455 0 0         if( @distinct_on )
456             {
457 0           assert( scalar @distinct_on == 1, "count of distinct is not yet supported for multiple PK models" );
458 0   0       my @fields = map { sprintf( "%s.%s",
  0            
459             ( $args{ '_table_alias' } or $self -> _db_table() ),
460             &__get_db_field_name( $_ ) ) } @distinct_on;
461 0           $rv = 'DISTINCT ' . join( ", ", @fields );
462             } else
463             {
464 0   0       warn( sprintf( "Don't know on what to DISTINCT (no PK and fields not passed) for %s",
465             ( ref( $self ) or $self ) ) );
466             }
467             }
468             }
469              
470 0           return $rv;
471             }
472              
473             sub __get_distinct_on_attrs
474             {
475 0     0     my ( $self, $d ) = @_;
476              
477 0           my @distinct_on = ();
478              
479 0 0         if( ref( $d ) eq 'ARRAY' )
480             {
481 0           foreach my $aname ( @{ $d } )
  0            
482             {
483 0   0       my $model_name = ( ref( $self ) or $self );
484 0 0         if( LittleORM::Model::Field -> this_is_field( $aname ) )
485             {
486 0           assert( $aname -> model() eq $model_name,
487             sprintf( "field %s from %s can not be used in model %s",
488             $aname -> base_attr(),
489             $aname -> model(),
490             $model_name ) );
491 0           $aname = $aname -> base_attr();
492             }
493              
494 0           assert( my $attr = $self -> meta() -> get_attribute( $aname ),
495             sprintf( 'invalid attr "%s" passed for model "%s"',
496             $aname,
497             $model_name ) );
498 0           push @distinct_on, $attr;
499             }
500            
501            
502             } else
503             {
504 0           @distinct_on = $self -> __find_primary_keys();
505             }
506            
507 0           return @distinct_on;
508            
509             }
510              
511             sub __form_sql_func_sql
512             {
513 0     0     my $self = shift;
514              
515 0           my @args = @_;
516 0           my %args = @args;
517              
518 0           my @where_args = $self -> __form_where( @args,
519             &__for_read() );
520              
521 0           my @tables_to_select_from = ( $self -> _db_table() );
522              
523 0 0         if( my $t = $args{ '_tables_to_select_from' } )
524             {
525 0           @tables_to_select_from = @{ $t };
  0            
526             }
527 0           assert( my $func = $args{ '_func' } );
528 0           my $dbf = $self -> __default_db_field_name_for_func( %args );
529              
530 0 0         if( my $attrname = $args{ '_attr' } )
531             {
532 0 0         if( LittleORM::Model::Field -> this_is_field( $attrname ) )
533             {
534 0           $dbf = $attrname -> form_field_name_for_db_select( $attrname -> determine_ta_for_field_from_another_model( $args{ '_tables_used' } ) );
535             } else
536             {
537 0           assert( my $attr = $self -> meta() -> find_attribute_by_name( $attrname ) );
538 0           $dbf = &__get_db_field_name( $attr );
539             }
540             }
541              
542 0   0       my $sql = sprintf( "SELECT %s%s(%s) FROM %s WHERE %s",
543             $self -> __form_sql_func_sql_more_fields( @args ),
544             $func,
545             $dbf,
546             join( ',', @tables_to_select_from ),
547             join( ' ' . ( $args{ '_logic' } or 'AND' ) . ' ', @where_args ) );
548              
549 0           $sql .= $self -> __form_additional_sql( @args );
550              
551 0           return $sql;
552             }
553              
554             sub __form_sql_func_sql_more_fields
555             {
556 0     0     my $self = shift;
557            
558 0           my @args = @_;
559 0           my %args = @args;
560 0           my $rv = '';
561            
562 0 0         if( my $t = $args{ '_groupby' } )
563             {
564 0           my @sqls = ();
565              
566 0   0       my $ta = ( $args{ '_table_alias' }
567             or
568             $self -> _db_table() );
569              
570 0           foreach my $grp ( @{ $t } )
  0            
571             {
572 0           my $f = undef;
573              
574 0 0         if( LittleORM::Model::Field -> this_is_field( $grp ) )
575             {
576 0           my $use_ta = $ta;
577              
578 0 0 0       if( $grp -> model() and ( $grp -> model() ne $self ) )
579             {
580 0           $use_ta = $grp -> determine_ta_for_field_from_another_model( $args{ '_tables_used' } );
581              
582             }
583 0           $f = $grp -> form_field_name_for_db_select_with_as( $use_ta );#form_field_name_for_db_select( $use_ta );
584              
585             } else
586             {
587 0           $f = sprintf( "%s.%s",
588             $ta,
589             &__get_db_field_name( $self -> meta() -> find_attribute_by_name( $grp ) ) );
590             }
591 0           push @sqls, $f;
592             }
593              
594 0           $rv .= join( ',', @sqls );
595 0           $rv .= ',';
596             }
597              
598 0           return $rv;
599             }
600              
601             sub count
602             {
603 0     0 0   my $self = shift;
604 0           return $self -> _sql_func_on_attr( 'count', '', @_ );
605              
606             }
607              
608             sub create
609             {
610 0     0 0   my $self = shift;
611 0           my @args = @_;
612              
613 0           my %args = $self -> __correct_insert_args( @args );
614 0           my $sql = $self -> __form_insert_sql( %args );
615              
616 0 0         if( $args{ '_debug' } )
617             {
618 0           return $sql;
619             }
620              
621 0           my $allok = undef;
622              
623             # if( my @pk = $self -> __find_primary_keys() )
624              
625 0           my $dbh = $self -> __get_dbh( @args,
626             &__for_write() );
627              
628             {
629 0           my $sth = &LittleORM::Db::prep( $sql, $dbh );
  0            
630 0           my $rc = $sth -> execute();
631              
632 0 0         if( $rc == 1 )
633             {
634             # $allok = 1;
635 0           my $data = $sth -> fetchrow_hashref();
636 0           $allok = $self -> create_one_return_value_item( $data, @args );
637              
638             # foreach my $pk ( @pk )
639             # {
640             # unless( $args{ $pk -> name() } )
641             # {
642             # my $field = &__get_db_field_name( $pk );
643             # $args{ $pk -> name() } = $data -> { $field };
644             # }
645             # }
646             }
647              
648 0           $sth -> finish();
649              
650             }
651              
652 0 0         if( $allok )
653             {
654 0           return $allok; #$self -> get( $self -> __leave_only_pk( %args ) );
655             }
656              
657 0           assert( 0, sprintf( "%s: %s", $sql, &LittleORM::Db::errstr( $dbh ) ) );
658             }
659              
660              
661              
662              
663              
664             sub _process_create_many_args
665             {
666 0     0     my $self = shift;
667              
668 0           my @args = @_;
669              
670              
671              
672 0           my $new_records_data = ();
673 0           my $extra_args_data = {};
674              
675 0           my $index_of_first_args_el_which_is_not_ref = ${ [ grep { not ref( $args[ $_ ] ) } ( 0 .. $#args ) ] }[ 0 ];
  0            
  0            
676              
677 0 0         if( $index_of_first_args_el_which_is_not_ref )
678             {
679              
680 0           @{ $new_records_data } = @args[ 0 .. $index_of_first_args_el_which_is_not_ref - 1 ];
  0            
681 0           %{ $extra_args_data } = @args[ $index_of_first_args_el_which_is_not_ref .. $#args ];
  0            
682             } else
683             {
684 0           $new_records_data = \@args;
685             }
686              
687 0           return ( $new_records_data,
688             $extra_args_data );
689              
690             }
691              
692             sub create_many
693             {
694 0     0 0   my $self = shift;
695              
696 0           my ( $new_records_data,
697             $extra_args_data ) = $self -> _process_create_many_args( @_ );
698              
699             {
700 0           assert( my $cnt = scalar @{ $new_records_data } );
  0            
  0            
701              
702 0           for( my $i = 0; $i < $cnt; $i ++ )
703             {
704 0           my %args = $self -> __correct_insert_args( @{ $new_records_data -> [ $i ] } );
  0            
705 0           $new_records_data -> [ $i ] = \%args;
706             }
707             }
708              
709 0           my $fields = undef;
710 0           my @values_sets = ();
711 0           my $dbh = $self -> __get_dbh( %{ $extra_args_data },
  0            
712             &__for_write() );
713              
714 0           foreach my $nrd ( @{ $new_records_data } )
  0            
715             {
716 0           my ( $f, $v ) = $self -> __form_fields_and_values_for_insert_sql( %{ $nrd } );
  0            
717 0   0       assert( $f and $v );
718 0 0         unless( defined $fields )
719             {
720 0           $fields = $f;
721             }
722 0           push @values_sets, join( ',', @{ $v } );
  0            
723             }
724              
725 0           my $sql = sprintf( "INSERT INTO %s (%s) VALUES %s RETURNING *",
726             $self -> _db_table(),
727 0           join( ',', @{ $fields } ),
728 0           join( ',', map { '(' . $_ . ')' } @values_sets ) );
729            
730              
731 0 0         if( $extra_args_data -> { '_debug' } )
732             {
733 0           return $sql;
734             }
735              
736 0           my @rv = ();
737              
738             {
739 0           my $sth = &LittleORM::Db::prep( $sql, $dbh ); #$self -> __get_dbh( %{ $extra_args_data } ) );
  0            
740 0           my $rc = $sth -> execute();
741              
742 0 0         if( $rc == scalar @{ $new_records_data } )
  0            
743             {
744 0           while( my $data = $sth -> fetchrow_hashref() )
745             {
746 0           my $o = $self -> create_one_return_value_item( $data, %{ $extra_args_data } );
  0            
747 0           push @rv, $o;
748             }
749              
750             } else
751             {
752 0           assert( 0, 'insert error' );
753             }
754            
755 0           $sth -> finish();
756             }
757              
758 0           return @rv;
759             }
760              
761             sub __leave_only_pk
762             {
763 0     0     my $self = shift;
764              
765 0           my %args = @_;
766 0           my %rv = ();
767              
768 0           foreach my $attr ( $self -> __find_primary_keys() )
769             {
770 0           my $aname = $attr -> name();
771 0 0         if( exists $args{ $aname } )
772             {
773 0           $rv{ $aname } = $args{ $aname };
774             }
775             }
776            
777 0 0         unless( %rv )
778             {
779 0           %rv = %args;
780             }
781              
782 0           return %rv;
783             }
784              
785             sub __find_attr_by_its_db_field_name
786             {
787 0     0     my ( $self, $db_field_name ) = @_;
788              
789 0           my $rv = undef;
790              
791             pgmxcobWi7lULIJW:
792 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
793             {
794 0 0         if( &__get_db_field_name( $attr ) eq $db_field_name )
795             {
796 0           $rv = $attr;
797 0           last pgmxcobWi7lULIJW;
798             }
799             }
800              
801 0           return $rv;
802             }
803              
804             sub update
805             {
806 0     0 0   my $self = shift;
807              
808 0           my %args = ();
809              
810 0 0         if( scalar @_ == 1 )
811             {
812 0           $args{ '_debug' } = $_[ 0 ];
813             } else
814             {
815 0           %args = @_;
816             }
817            
818 0           my @upadte_pairs = $self -> __get_update_pairs_for_update_request( %args );
819              
820 0           my $where = $self -> __form_update_request_where_part( %args );
821 0           my $sql = sprintf( 'UPDATE %s SET %s WHERE %s',
822             $self -> _db_table(),
823             join( ',', @upadte_pairs ),
824             $where );
825              
826 0           my $rc = undef;
827 0           my $dbh = $self -> __get_dbh( &__for_write() );
828              
829 0 0         if( $args{ '_debug' } )
830             {
831 0           return $sql;
832             } else
833             {
834 0           $rc = &LittleORM::Db::doit( $sql, $dbh );
835            
836 0 0         if( ref( $self ) )
837             {
838 0 0         if( $rc != 1 )
839             {
840 0           assert( 0, sprintf( "%s: %s", $sql, &LittleORM::Db::errstr( $dbh ) ) );
841             }
842             }
843             }
844 0           return $rc;
845             }
846              
847              
848             sub __get_update_pairs_for_update_request
849             {
850 0     0     my $self = shift;
851 0           my %args = @_;
852              
853 0           my @upadte_pairs = ();
854              
855              
856 0 0         if( ref( $self ) )
857             {
858 0           @upadte_pairs = $self -> __get_update_pairs_for_update_request_called_from_instance( %args );
859             } else
860             {
861 0           @upadte_pairs = $self -> __get_update_pairs_for_update_request_called_from_class( %args );
862             }
863              
864 0           return @upadte_pairs;
865              
866             }
867              
868             sub __get_update_pairs_for_update_request_called_from_instance
869             {
870 0     0     my $self = shift;
871 0           my %args = @_;
872              
873 0           my @upadte_pairs = ();
874              
875             ETxc0WxZs0boLUm1:
876 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
877             {
878 0 0         if( $self -> __should_ignore_on_write( $attr ) )
879             {
880 0           next ETxc0WxZs0boLUm1;
881             }
882            
883 0           my $aname = $attr -> name();
884            
885 0 0         if( exists $args{ $aname } )
886             {
887 0           $self -> $aname( $args{ $aname } );
888             }
889            
890 0           my $value = &__prep_value_for_db( $attr, $self -> $aname() );
891            
892 0           push @upadte_pairs, sprintf( '%s=%s',
893             &__get_db_field_name( $attr ),
894             &LittleORM::Db::dbq( $value, $self -> __get_dbh( &__for_write() ) ) );
895            
896             }
897            
898 0           return @upadte_pairs;
899              
900             }
901              
902             sub __get_update_pairs_for_update_request_called_from_class
903             {
904 0     0     my $self = shift;
905 0           my %args = @_;
906              
907 0           my @upadte_pairs = ();
908              
909 0           while( my ( $k, $v ) = each %args )
910             {
911 0 0         unless( $k =~ /^_/ ) # only system props and no real class attrs should start with underscore
912             {
913 0           assert( my $attr = $self -> meta() -> find_attribute_by_name( $k ) );
914              
915 0 0         if( $self -> __should_ignore_on_write( $attr ) )
916             {
917 0           assert( 0, 'attr which should be ignored passed into update:' . $k );
918             } else
919             {
920 0           my $value = &__prep_value_for_db( $attr, $v );
921 0           my $typecast = '';
922              
923 0 0         if( LittleORM::Model::Field -> this_is_field( $value ) )
924             {
925 0 0 0       if( ( my $t1 = &__descr_attr( $attr, 'db_field_type' ) )
926             and
927             ( my $t2 = $value -> db_field_type() ) )
928             {
929 0 0         unless( $t1 eq $t2 )
930             {
931 0           $typecast = '::' . $t1;
932             }
933             }
934 0           $value = $value -> form_field_name_for_db_select();
935              
936             } else
937             {
938 0           $value = &LittleORM::Db::dbq( $value, $self -> __get_dbh( &__for_write() ) );
939             }
940              
941 0           push @upadte_pairs, sprintf( '%s=%s%s',
942             &__get_db_field_name( $attr ),
943             $value,
944             $typecast );
945             }
946              
947             }
948             }
949            
950 0           return @upadte_pairs;
951             }
952              
953             sub __form_update_request_where_part
954             {
955 0     0     my $self = shift;
956 0           my %args = @_;
957              
958 0           my @where = ();
959              
960 0 0         if( my $w = $args{ '_where' } )
961             {
962 0           assert( not ref( $self ) ); # only class call, not instance call
963 0 0         if( ref( $w ) eq 'ARRAY' )
964             {
965 0           @where = $self -> __form_where( @{ $w },
  0            
966             &__for_write() );
967             } else
968             {
969 0           push @where, $w;
970             }
971              
972             } else
973             {
974 0           assert( my @pkattr = $self -> __find_primary_keys(), 'cant update without primary key' );
975              
976 0           my %where_args = ();
977              
978 0           foreach my $pkattr ( @pkattr )
979             {
980 0           my $pkname = $pkattr -> name();
981 0           $where_args{ $pkname } = $self -> $pkname();
982             }
983 0           @where = $self -> __form_where( %where_args,
984             &__for_write() );
985             }
986              
987 0           assert( my $where = join( ' AND ', @where ) );
988              
989 0           return $where;
990             }
991              
992             sub copy
993             {
994 0     0 0   my $self = shift;
995              
996 0           my %args = @_;
997              
998 0           assert( my $class = ref( $self ), 'this is object method' );
999              
1000 0           my %copied_args = %args;
1001              
1002             kdCcjt3iG8jOfthJ:
1003 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
1004             {
1005 0 0         if( $self -> __should_ignore_on_write( $attr ) )
1006             {
1007 0           next kdCcjt3iG8jOfthJ;
1008             }
1009 0           my $aname = $attr -> name();
1010              
1011 0 0         unless( exists $copied_args{ $aname } )
1012             {
1013 0           $copied_args{ $aname } = $self -> $aname();
1014             }
1015             }
1016              
1017 0           return $class -> create( %copied_args );
1018             }
1019              
1020             sub delete
1021             {
1022 0     0 0   my $self = shift;
1023              
1024 0           my @args = @_;
1025 0           my %args = @args;
1026              
1027 0           my $sql = $self -> __form_delete_sql( @args );
1028              
1029 0 0         if( $args{ '_debug' } )
1030             {
1031 0           return $sql;
1032             }
1033              
1034 0           my $rc = &LittleORM::Db::doit( $sql, $self -> __get_dbh( @args,
1035             &__for_write() ) );
1036              
1037 0           return $rc;
1038             }
1039              
1040             sub meta_change_attr
1041             {
1042 0     0 0   my $self = shift;
1043              
1044 0           my $arg = shift;
1045              
1046 0           my %attrs = @_;
1047              
1048 0           my $arg_obj = $self -> meta() -> find_attribute_by_name( $arg );
1049              
1050 0           my $cloned_arg_obj = $arg_obj -> clone();
1051              
1052 0   0 0     my $d = ( $cloned_arg_obj -> description() or sub {} -> () );
  0            
1053              
1054 0           my %new_description = %{ $d };
  0            
1055              
1056 0           while( my ( $k, $v ) = each %attrs )
1057             {
1058 0 0         if( $v )
1059             {
1060 0           $new_description{ $k } = $v;
1061             } else
1062             {
1063 0           delete $new_description{ $k };
1064             }
1065             }
1066              
1067 0           $cloned_arg_obj -> description( \%new_description );
1068              
1069 0           $self -> meta() -> add_attribute( $cloned_arg_obj );
1070             }
1071              
1072             sub BUILD
1073             {
1074 0     0 0   my $self = shift;
1075              
1076 0           my $orm_initialized_attr_desc_option = '__orm_initialized_attr_' . ref( $self );
1077 0           my $orm_initialized_attr_desc_option_hf = '__orm_initialized_attr_has_field_';
1078              
1079              
1080             FXOINoqUOvIG1kAG:
1081 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
1082             {
1083 0           my $aname = $attr -> name();
1084              
1085 0 0 0       if( $self -> __should_ignore( $attr )
      0        
1086             or
1087             &__descr_attr( $attr, $orm_initialized_attr_desc_option )
1088             or
1089             &__descr_attr( $attr, $orm_initialized_attr_desc_option_hf ) )
1090             {
1091             # internal attrs start with underscore, skip them
1092 0           next FXOINoqUOvIG1kAG;
1093             }
1094              
1095             {
1096              
1097 0   0       my $newdescr = ( &__descr_or_undef( $attr ) or {} );
  0            
1098 0           $newdescr -> { $orm_initialized_attr_desc_option } = 1;
1099              
1100 0           my $predicate = $attr -> predicate();
1101 0           my $trigger = $attr -> trigger();
1102 0           my $clearer = $attr -> clearer(); # change made by Kain
1103             # I really need this sometimes in case of processing thousands of objects
1104             # and manual cleanup so I'm avoiding cache-related memleaks
1105             # so if you want to give me whole server RAM - wipe it out :)
1106              
1107 0 0         my $handles = ( $attr -> has_handles() ? $attr -> handles() : undef ); # also made by kain
1108              
1109 0           my $orig_method = $self -> meta() -> get_method( $aname );
1110              
1111 0           $attr -> default( undef );
1112             $self -> meta() -> add_attribute( $aname, ( is => 'rw',
1113             isa => $attr -> { 'isa' },
1114             coerce => $attr -> { 'coerce' },
1115              
1116              
1117             ( defined $predicate ? ( predicate => $predicate ) : () ),
1118             ( defined $trigger ? ( trigger => $trigger ) : () ),
1119             ( defined $clearer ? ( clearer => $clearer ) : () ),
1120             ( defined $handles ? ( handles => $handles ) : () ),
1121              
1122             lazy => 1,
1123             metaclass => 'LittleORM::Meta::Attribute',
1124             description => $newdescr,
1125 0 0   0     default => sub { $_[ 0 ] -> __lazy_build_value( $attr ) } ) );
  0 0          
    0          
    0          
1126              
1127 0 0 0       if( $orig_method and $orig_method -> isa( 'Class::MOP::Method::Wrapped' ) )
1128             {
1129 0           my $new_method = $self -> meta() -> get_method( $aname );
1130 0           my $new_meta_method = Class::MOP::Method::Wrapped -> wrap( $new_method );
1131            
1132 0           map { $new_meta_method -> add_around_modifier( $_ ) } $orig_method -> around_modifiers();
  0            
1133 0           map { $new_meta_method -> add_before_modifier( $_ ) } $orig_method -> before_modifiers();
  0            
1134 0           map { $new_meta_method -> add_after_modifier( $_ ) } $orig_method -> after_modifiers();
  0            
1135            
1136 0           $self -> meta() -> add_method( $aname, $new_meta_method );
1137             }
1138             }
1139             }
1140             }
1141              
1142             sub __lazy_build_value
1143             {
1144 0     0     my $self = shift;
1145 0           my $attr = shift;
1146              
1147 0           my $rec_field_name = &__get_db_field_name( $attr );
1148              
1149 0           my $t = $self -> __lazy_build_value_actual( $attr,
1150             $self -> _rec() -> { $rec_field_name } );
1151              
1152 0           return $t;
1153             }
1154              
1155              
1156             sub __lazy_build_value_actual
1157             {
1158 0     0     my ( $self, $attr, $t ) = @_;
1159              
1160 0           my $coerce_from = &__descr_attr( $attr, 'coerce_from' );
1161              
1162 0 0         if( defined $coerce_from )
    0          
1163             {
1164 0           $t = $coerce_from -> ( $t );
1165            
1166             } elsif( my $foreign_key = &__descr_attr( $attr, 'foreign_key' ) )
1167             {
1168 0 0         if( $foreign_key eq 'yes' )
1169             {
1170             # sugar
1171 0           assert( $attr -> has_type_constraint() );
1172 0           $foreign_key = $attr -> type_constraint() -> name();
1173             }
1174              
1175 0           &__load_module( $foreign_key );
1176              
1177 0           my $foreign_key_attr_name = &__descr_attr( $attr, 'foreign_key_attr_name' );
1178              
1179 0 0         unless( $foreign_key_attr_name )
1180             {
1181 0           my $his_pk = $foreign_key -> __find_primary_key();
1182 0           $foreign_key_attr_name = $his_pk -> name();
1183             }
1184            
1185 0   0       $t = $foreign_key -> get( $foreign_key_attr_name => $t,
1186             _dbh => ( $foreign_key -> __get_dbh( &__for_read() )
1187             or
1188             $self -> __get_dbh( &__for_read() ) ) );
1189             }
1190            
1191 0           return $t;
1192              
1193             }
1194              
1195              
1196             sub __load_module
1197             {
1198 0     0     my $mn = shift;
1199              
1200 0           Module::Load::load( $mn );
1201              
1202             }
1203              
1204             sub __correct_insert_args
1205             {
1206 0     0     my $self = shift;
1207 0           my %args = @_;
1208              
1209 0           my $dbh = $self -> __get_dbh( %args,
1210             &__for_write() );
1211              
1212             wus2eQ_YY2I_r3rb:
1213 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
1214             {
1215              
1216 0 0 0       if( &__descr_attr( $attr, 'ignore' )
1217             or
1218             &__descr_attr( $attr, 'ignore_write' ) )
1219             {
1220 0           next wus2eQ_YY2I_r3rb;
1221             }
1222              
1223 0           my $aname = $attr -> name();
1224 0 0         unless( exists $args{ $aname } )
1225             {
1226 0 0         if( my $seqname = &__descr_attr( $attr, 'sequence' ) )
1227             {
1228 0           my $nv = &LittleORM::Db::nextval( $seqname, $dbh );
1229              
1230 0           $args{ $aname } = $nv;
1231             } else
1232             {
1233 0           $args{ $aname } = &__default_insert_field_cached();
1234             }
1235             }
1236             }
1237              
1238 0           return %args;
1239             }
1240              
1241             {
1242             my $rv = undef;
1243              
1244             sub __default_insert_field_cached
1245             {
1246 0 0   0     unless( $rv )
1247             {
1248 0           $rv = LittleORM::Model::Field -> new( db_func => 'DEFAULT',
1249             db_func_tpl => '%s' );
1250             }
1251 0           return $rv;
1252             }
1253             }
1254              
1255              
1256             sub __form_fields_and_values_for_insert_sql
1257             {
1258 0     0     my $self = shift;
1259 0           my %args = @_;
1260              
1261 0           my @fields = ();
1262 0           my @values = ();
1263              
1264 0           my $dbh = $self -> __get_dbh( %args,
1265             &__for_write() );
1266              
1267             XmXRGqnrCTqWH52Z:
1268 0           foreach my $arg ( sort keys %args ) # sort here is crucial for create_many() , see test 040
1269             {
1270 0           my $val = $args{ $arg };
1271 0 0         if( $arg =~ /^_/ )
1272             {
1273 0           next XmXRGqnrCTqWH52Z;
1274             }
1275              
1276 0           assert( my $attr = $self -> meta() -> find_attribute_by_name( $arg ),
1277             sprintf( 'invalid attr name passed: %s', $arg ) );
1278              
1279 0 0 0       if( &__descr_attr( $attr, 'ignore' )
1280             or
1281             &__descr_attr( $attr, 'ignore_write' ) )
1282             {
1283 0           next XmXRGqnrCTqWH52Z;
1284             }
1285              
1286             ( undef,
1287 0           $val,
1288             undef,
1289             undef,
1290             undef ) = $self -> determine_op_and_col_and_correct_val( $arg,
1291             $val,
1292             $self -> _db_table(),
1293             { %args,
1294             __we_do_insert_now => 'yes' },
1295             $dbh );
1296              
1297 0           my $field_name = &__get_db_field_name( $attr );
1298            
1299 0           push @fields, $field_name;
1300 0           push @values, $val;
1301             }
1302              
1303 0           return ( \@fields, \@values );
1304             }
1305              
1306              
1307              
1308             sub __form_insert_sql
1309             {
1310 0     0     my $self = shift;
1311              
1312 0           my %args = @_;
1313 0           my ( $fields, $values ) = $self -> __form_fields_and_values_for_insert_sql( %args );
1314            
1315 0           my $dbh = $self -> __get_dbh( %args,
1316             &__for_write() );
1317 0           my $sql = sprintf( "INSERT INTO %s (%s) VALUES (%s) RETURNING *",
1318             $self -> _db_table(),
1319 0           join( ',', @{ $fields } ),
1320 0           join( ',', @{ $values } ) );
1321              
1322 0           return $sql;
1323             }
1324              
1325             sub __prep_value_for_db
1326             {
1327 0     0     my ( $attr, $value ) = @_;
1328              
1329 0           my $isa = $attr -> { 'isa' };
1330 0           my $perform_coercion = 1;
1331              
1332 0 0         if( LittleORM::Model::Value -> this_is_value( $value ) )
1333             {
1334 0 0         unless( $value -> orm_coerce() )
1335             {
1336 0           $perform_coercion = 0;
1337             }
1338 0           $value = $value -> value(); # %)
1339             }
1340              
1341 0 0         if( $perform_coercion )
1342             {
1343 0           my $ftc = find_type_constraint( $isa );
1344              
1345 0 0 0       if( $ftc and $ftc -> has_coercion() )
1346             {
1347 0           $value = $ftc -> coerce( $value );
1348             }
1349             }
1350              
1351 0           my $rv = $value;
1352              
1353 0 0         unless( LittleORM::Model::Field -> this_is_field( $value ) )
1354             {
1355 0 0 0       if( $perform_coercion
1356             and
1357             ( my $coerce_to = &__descr_attr( $attr, 'coerce_to' ) ) )
1358             {
1359 0           $rv = $coerce_to -> ( $value );
1360             }
1361            
1362 0 0 0       if( blessed( $value ) and &__descr_attr( $attr, 'foreign_key' ) )
1363             {
1364 0           my $foreign_key_attr_name = &__descr_attr( $attr, 'foreign_key_attr_name' );
1365            
1366 0 0         unless( $foreign_key_attr_name )
1367             {
1368 0           my $his_pk = $value -> __find_primary_key();
1369 0           $foreign_key_attr_name = $his_pk -> name();
1370             }
1371 0           $rv = $value -> $foreign_key_attr_name();
1372             }
1373             }
1374            
1375 0           return $rv;
1376             }
1377              
1378             sub __form_delete_sql
1379             {
1380 0     0     my $self = shift;
1381              
1382 0           my @args = @_;
1383 0           my %args = @args;
1384              
1385 0 0         if( ref( $self ) )
1386             {
1387 0 0         if( my @pk = $self -> __find_primary_keys() )
1388             {
1389 0           foreach my $pk ( @pk )
1390             {
1391              
1392 0           my $pkname = $pk -> name();
1393 0           $args{ $pkname } = $self -> $pkname();
1394             }
1395             } else
1396             {
1397 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
1398             {
1399 0           my $aname = $attr -> name();
1400 0           $args{ $aname } = $self -> $aname();
1401             }
1402             }
1403             }
1404              
1405 0           my @where_args = $self -> __form_where( %args,
1406             &__for_write() );
1407              
1408 0           my $sql = sprintf( "DELETE FROM %s WHERE %s", $self -> _db_table(), join( ' AND ', @where_args ) );
1409              
1410 0           return $sql;
1411             }
1412              
1413             sub __should_ignore_on_write
1414             {
1415 0     0     my ( $self, $attr ) = @_;
1416 0           my $rv = $self -> __should_ignore( $attr );
1417              
1418 0 0         unless( $rv )
1419             {
1420 0 0 0       if( &__descr_attr( $attr, 'primary_key' )
1421             or
1422             &__descr_attr( $attr, 'ignore_write' ) )
1423             {
1424 0           $rv = 1;
1425             }
1426             }
1427              
1428 0           return $rv;
1429             }
1430              
1431             sub __should_ignore
1432             {
1433 0     0     my ( $self, $attr ) = @_;
1434 0           my $rv = 0;
1435              
1436 0 0         unless( $rv )
1437             {
1438 0           my $aname = $attr -> name();
1439 0 0         if( $aname =~ /^_/ )
1440             {
1441 0           $rv = 1;
1442             }
1443             }
1444              
1445 0 0         unless( $rv )
1446             {
1447              
1448 0 0         if( &__descr_attr( $attr, 'ignore' ) )
1449             {
1450 0           $rv = 1;
1451             }
1452             }
1453              
1454 0           return $rv;
1455             }
1456              
1457             sub __collect_field_names
1458             {
1459 0     0     my $self = shift;
1460 0           my %args = @_;
1461              
1462 0           my @rv = ();
1463              
1464 0           my $groupby = undef;
1465 0 0         if( my $t = $args{ '_groupby' } )
1466             {
1467 0           my %t = map { $_ => 1 } grep { not LittleORM::Model::Field -> this_is_field( $_ ) } @{ $t };
  0            
  0            
  0            
1468 0           $groupby = \%t;
1469             }
1470              
1471 0           my $field_set = $args{ '_fieldset' };
1472              
1473 0   0       my $ta = ( $args{ '_table_alias' }
1474             or
1475             $self -> _db_table() );
1476              
1477             QGVfwMGQEd15mtsn:
1478 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
1479             {
1480 0 0         if( $self -> __should_ignore( $attr ) )
1481             {
1482 0           next QGVfwMGQEd15mtsn;
1483             }
1484              
1485 0           my $aname = $attr -> name();
1486              
1487 0           my $db_fn = $ta .
1488             '.' .
1489             &__get_db_field_name( $attr );
1490              
1491 0 0         if( $groupby )
1492             {
1493 0 0         if( exists $groupby -> { $aname } )
1494             {
1495 0           push @rv, $db_fn;
1496             }
1497              
1498             } else
1499             {
1500 0 0         unless( $field_set )
1501             {
1502 0           push @rv, $db_fn;
1503             }
1504             }
1505             }
1506              
1507 0 0         if( $field_set )
1508             {
1509 0           foreach my $f ( @{ $field_set } )
  0            
1510             {
1511 0 0         unless( LittleORM::Model::Field -> this_is_field( $f ) )
1512             {
1513 0           $f = $self -> borrow_field( $f,
1514             select_as => &__get_db_field_name( $self -> meta() -> find_attribute_by_name( $f ) ) );
1515             }
1516              
1517 0           my $select = $f -> form_field_name_for_db_select_with_as( $ta );
1518              
1519 0 0         if( $f -> model() )
1520             {
1521             # unless( $f -> model() eq $self )
1522             # {
1523 0           my $ta = $f -> determine_ta_for_field_from_another_model( $args{ '_tables_used' } );
1524 0           $select = $f -> form_field_name_for_db_select_with_as( $ta );
1525             # }
1526             }
1527 0           push @rv, $select;# . ' AS ' . $f -> select_as();
1528             }
1529             }
1530              
1531 0           return @rv;
1532             }
1533              
1534             sub __form_get_sql
1535             {
1536 0     0     my $self = shift;
1537              
1538 0           my @args = @_;
1539 0           my %args = @args;
1540              
1541 0           my @where_args = $self -> __form_where( @args,
1542             &__for_read() );
1543              
1544 0           my @fields_names = $self -> __collect_field_names( @args );
1545              
1546 0           my @tables_to_select_from = ( $self -> _db_table() );
1547              
1548 0 0         if( my $t = $args{ '_tables_to_select_from' } )
1549             {
1550 0           @tables_to_select_from = @{ $t };
  0            
1551             }
1552              
1553 0           my $distinct_select = '';
1554              
1555 0 0         if( my $d = $args{ '_distinct' } )
1556             {
1557 0           $distinct_select = 'DISTINCT';
1558              
1559 0 0         if( my @distinct_on = $self -> __get_distinct_on_attrs( $d ) )
1560             {
1561 0   0       my @fields = map { sprintf( "%s.%s",
  0            
1562             ( $args{ '_table_alias' } or $self -> _db_table() ),
1563             &__get_db_field_name( $_ ) ) } @distinct_on;
1564              
1565 0           $distinct_select .= sprintf( " ON ( %s ) ", join( ',', @fields ) );
1566             } else
1567             {
1568              
1569 0   0       warn( sprintf( "Don't know on what to DISTINCT (no PK and fields not passed) for %s",
1570             ( ref( $self ) or $self ) ) );
1571              
1572             }
1573             }
1574              
1575 0   0       my $sql = sprintf( "SELECT %s %s FROM %s WHERE %s",
1576             $distinct_select,
1577             join( ',', @fields_names ),
1578             join( ',', @tables_to_select_from ),
1579             join( ' ' . ( $args{ '_logic' } or 'AND' ) . ' ', @where_args ) );
1580              
1581 0           $sql .= $self -> __form_additional_sql( @args );
1582              
1583 0           return $sql;
1584             }
1585              
1586             sub __form_additional_sql
1587             {
1588 0     0     my $self = shift;
1589              
1590 0           my @args = @_;
1591 0           my %args = @args;
1592              
1593 0           my $sql = '';
1594              
1595 0           $sql .= $self -> __form_additional_sql_groupby( @args );
1596              
1597 0 0         if( my $t = $args{ '_sortby' } )
1598             {
1599 0 0         if( ref( $t ) eq 'HASH' )
    0          
1600             {
1601             # then its like
1602             # { field1 => 'DESC',
1603             # field2 => 'ASC' ... }
1604              
1605 0           my @pairs = ();
1606              
1607 0           while( my ( $k, $sort_order ) = each %{ $t } )
  0            
1608             {
1609 0           my $dbf = $k;
1610              
1611 0 0         if( my $t = $self -> meta() -> find_attribute_by_name( $k ) )
1612             {
1613 0   0       $dbf = ( $args{ '_table_alias' }
1614             or
1615             $self -> _db_table() ) .
1616             '.' .
1617             &__get_db_field_name( $t );
1618              
1619             }
1620              
1621 0           push @pairs, sprintf( '%s %s',
1622             $dbf,
1623             $sort_order );
1624             }
1625 0           $sql .= ' ORDER BY ' . join( ',', @pairs );
1626             } elsif( ref( $t ) eq 'ARRAY' )
1627             {
1628 0           my @pairs = ();
1629              
1630 0           my @arr = @{ $t };
  0            
1631              
1632 0           while( @arr )
1633             {
1634 0           my $k = shift @arr;
1635 0           my $sort_order = shift @arr;
1636              
1637 0           my $dbf = $k;
1638 0 0         if( my $t = $self -> meta() -> find_attribute_by_name( $k ) )
    0          
1639             {
1640 0   0       $dbf = ( $args{ '_table_alias' }
1641             or
1642             $self -> _db_table() ) .
1643             '.' .
1644             &__get_db_field_name( $t );
1645             } elsif( LittleORM::Model::Field -> this_is_field( $k ) )
1646             {
1647 0   0       $dbf = $k -> form_field_name_for_db_select( $k -> table_alias()
1648             or
1649             $args{ '_table_alias' }
1650             or
1651             $self -> _db_table() );
1652             }
1653              
1654 0   0       push @pairs, sprintf( '%s %s',
1655             ( $dbf or $k ),
1656             $sort_order );
1657             }
1658 0           $sql .= ' ORDER BY ' . join( ',', @pairs );
1659              
1660             } else
1661             {
1662             # then its attr name and unspecified order
1663 0           my $dbf = $t;
1664              
1665 0 0         if( my $t1 = $self -> meta() -> find_attribute_by_name( $t ) )
    0          
1666             {
1667 0   0       $dbf = ( $args{ '_table_alias' }
1668             or
1669             $self -> _db_table() ) . '.' . &__get_db_field_name( $t1 );
1670             } elsif( LittleORM::Model::Field -> this_is_field( $t ) )
1671             {
1672 0   0       $dbf = $t -> form_field_name_for_db_select( $t -> table_alias()
1673             or
1674             $args{ '_table_alias' }
1675             or
1676             $self -> _db_table() );
1677             }
1678              
1679 0           $sql .= ' ORDER BY ' . $dbf;
1680             }
1681             }
1682              
1683 0 0 0       if( my $t = int( $args{ '_limit' } or 0 ) )
1684             {
1685 0           $sql .= sprintf( ' LIMIT %d ', $t );
1686             }
1687              
1688 0 0 0       if( my $t = int( $args{ '_offset' } or 0 ) )
1689             {
1690 0           $sql .= sprintf( ' OFFSET %d ', $t );
1691             }
1692              
1693 0           return $sql;
1694             }
1695              
1696             sub __form_additional_sql_groupby
1697             {
1698 0     0     my $self = shift;
1699 0           my %args = @_;
1700 0           my $rv = '';
1701 0 0         if( my $t = $args{ '_groupby' } )
1702             {
1703 0           $rv = ' GROUP BY ';
1704              
1705              
1706 0           my @sqls = ();
1707              
1708 0   0       my $ta = ( $args{ '_table_alias' }
1709             or
1710             $self -> _db_table() );
1711              
1712 0           foreach my $grp ( @{ $t } )
  0            
1713             {
1714 0           my $f = undef;
1715              
1716 0 0         if( LittleORM::Model::Field -> this_is_field( $grp ) )
1717             {
1718             # $self -> assert_field_from_this_model( $grp );
1719              
1720 0           my $use_ta = $ta;
1721              
1722 0 0 0       if( $grp -> model() and ( $grp -> model() ne $self ) )
1723             {
1724 0           $use_ta = $grp -> determine_ta_for_field_from_another_model( $args{ '_tables_used' } );
1725             }
1726              
1727 0           $f = $grp -> form_field_name_for_db_select( $use_ta );
1728              
1729             } else
1730             {
1731 0           $f = sprintf( "%s.%s",
1732             $ta,
1733             &__get_db_field_name( $self -> meta() -> find_attribute_by_name( $grp ) ) );
1734             }
1735 0           push @sqls, $f;
1736             }
1737              
1738 0           $rv .= join( ',', @sqls );
1739             }
1740              
1741 0           return $rv;
1742             }
1743              
1744             sub __process_clause_sys_arg_in_form_where
1745             {
1746 0     0     my ( $self, $val, $args ) = @_;
1747              
1748 0 0         if( ref( $val ) eq 'ARRAY' )
1749             {
1750 0           my %more_args = ();
1751            
1752 0 0         if( my $ta = $args -> { '_table_alias' } )
1753             {
1754 0           $more_args{ 'table_alias' } = $ta;
1755             }
1756            
1757 0           $val = $self -> clause( @{ $val },
  0            
1758             %more_args );
1759            
1760 0           assert( ref( $val ) eq 'LittleORM::Clause' );
1761             } else
1762             {
1763 0           assert( ref( $val ) eq 'LittleORM::Clause' );
1764 0 0         if( my $ta = $args -> { '_table_alias' } )
1765             {
1766 0 0         unless( $val -> table_alias() )
1767             {
1768 0           my $copy = bless( { %{ $val } }, ref $val );
  0            
1769 0           $val = $copy;
1770 0           $val -> table_alias( $ta );
1771             }
1772             }
1773             }
1774 0           return $val;
1775             }
1776              
1777             sub __form_where
1778             {
1779 0     0     my $self = shift;
1780              
1781 0           my @args = @_;
1782 0           my %args = @args;
1783              
1784 0           my @where_args = ();
1785 0           my $dbh = $self -> __get_dbh( @args );
1786              
1787              
1788             fhFwaEknUtY5xwNr:
1789 0           while( my $attr = shift @args )
1790             {
1791 0           my $val = shift @args;
1792              
1793 0 0         if( $attr eq '_where' )
    0          
1794             {
1795 0           push @where_args, $val;
1796              
1797             } elsif( $attr eq '_clause' )
1798             {
1799 0           $val = $self -> __process_clause_sys_arg_in_form_where( $val,
1800             \%args );
1801 0           push @where_args, $val -> sql();
1802             }
1803              
1804 0 0         if( $attr =~ /^_/ ) # skip system agrs, they start with underscore
1805             {
1806 0           next fhFwaEknUtY5xwNr;
1807             }
1808              
1809 0           my ( $op, $col ) = ( undef, undef );
1810 0           my ( $val1_type, $val2_type ) = ( undef, undef );
1811 0   0       my $ta = ( $args{ '_table_alias' } or $self -> _db_table() );
1812              
1813 0           ( $op,
1814             $val,
1815             $col,
1816             $val1_type,
1817             $val2_type ) = $self -> determine_op_and_col_and_correct_val( $attr, $val, $ta, \%args, $dbh ); # this
1818             # is
1819             # not
1820             # a
1821             # structured
1822             # method,
1823             # this
1824             # is
1825             # just
1826             # code
1827             # moved
1828             # away
1829             # from
1830             # growing
1831             # too
1832             # big
1833             # function,
1834             # hilarious
1835             # comment
1836             # formatting
1837             # btw,
1838             # thx
1839             # emacs
1840 0 0         if( $op )
1841             {
1842 0           my $f = $col;
1843              
1844 0 0 0       unless( ( exists $args{ '_include_table_alias_into_sql' } )
1845             and
1846             ( $args{ '_include_table_alias_into_sql' } == 0 ) )
1847             {
1848 0           $f = $ta . '.' . $f;
1849             }
1850            
1851 0 0         if( LittleORM::Model::Field -> this_is_field( $attr ) )
1852             {
1853 0   0       $f = $attr -> form_field_name_for_db_select( $attr -> table_alias() or $ta );
1854             }
1855              
1856 0           my $cast = '';
1857              
1858 0 0 0       if( $val1_type and $val2_type and ( $val1_type ne $val2_type ) )
      0        
1859             {
1860 0           $cast = '::' . $val1_type;
1861             }
1862              
1863 0           push @where_args, sprintf( '%s %s %s%s',
1864             $f,
1865             $op,
1866             $val,
1867             $cast );
1868             }
1869             }
1870              
1871 0 0         unless( @where_args )
1872             {
1873 0           @where_args = ( '3=3' );
1874             }
1875             # print Data::Dumper::Dumper( \@where_args );
1876             # print Carp::longmess() . "\n\n\n";
1877 0           return @where_args;
1878             }
1879              
1880             sub determine_op_and_col_and_correct_val
1881             {
1882 0     0 0   my ( $self, $attr, $val, $ta, $args, $dbh ) = @_;
1883              
1884 0           my $op = '=';
1885 0           my $col = 'UNUSED';
1886 0           my ( $dbf_type1, $dbf_type2 ) = ( undef, undef );
1887 0           my $class_attr = undef;
1888            
1889 0 0         unless( LittleORM::Model::Field -> this_is_field( $attr ) )
1890             {
1891 0           assert( $class_attr = $self -> meta() -> find_attribute_by_name( $attr ),
1892             sprintf( 'invalid attribute: "%s"', $attr ) );
1893            
1894 0 0         if( &__descr_attr( $class_attr, 'ignore' ) )
1895             {
1896 0           $op = undef;
1897             } else
1898             {
1899 0           $attr = $self -> borrow_field( $class_attr -> name() );
1900 0           $col = &__get_db_field_name( $class_attr );
1901             }
1902             }
1903              
1904 0 0 0       if( $op and LittleORM::Model::Field -> this_is_field( $attr ) )
1905             {
1906 0 0         unless( $class_attr )
1907             {
1908 0 0         if( $attr -> base_attr() )
1909             {
1910 0           assert( $class_attr = $attr -> model() -> meta() -> find_attribute_by_name( $attr -> base_attr() ) );
1911             }
1912             }
1913              
1914 0           $dbf_type1 = $attr -> db_field_type();
1915              
1916 0 0         if( ref( $val ) eq 'HASH' )
    0          
    0          
1917             {
1918 0 0         if( $args -> { '__we_do_insert_now' } )
1919             {
1920 0           $val = $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $val ),
1921             $ta,
1922             $args,
1923             $dbh );
1924             } else
1925             {
1926 0           my %t = %{ $val };
  0            
1927 0           my $rval = undef;
1928 0           ( $op, $rval ) = each %t;
1929            
1930 0 0         if( ref( $rval ) eq 'ARRAY' )
1931             {
1932 0           $val = sprintf( '(%s)', join( ',', map { $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $_ ),
  0            
1933             $ta,
1934             $args,
1935 0           $dbh ) } @{ $rval } ) );
1936            
1937             } else
1938             {
1939 0           $val = $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $rval ),
1940             $ta,
1941             $args,
1942             $dbh );
1943            
1944             }
1945             }
1946            
1947             } elsif( ref( $val ) eq 'ARRAY' )
1948             {
1949 0 0         if( $args -> { '__we_do_insert_now' } )
1950             {
1951              
1952 0           $val = &LittleORM::Db::dbq( $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $val ),
1953             $ta,
1954             $args ),
1955             $dbh );
1956              
1957              
1958             # my @values = map { $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $_ ),
1959             # $ta,
1960             # $args ) } @{ $val };
1961             # $val = &LittleORM::Db::dbq( \@values, $dbh );
1962              
1963             } else
1964             {
1965              
1966 0 0         if( my @values = map { $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $_ ),
  0            
  0            
1967             $ta,
1968             $args,
1969             $dbh ) } @{ $val } )
1970             {
1971 0           $val = sprintf( "(%s)", join( ',', @values ) );
1972 0           $op = 'IN';
1973             } else
1974             {
1975 0           $val = "ANY('{}')";
1976             }
1977             }
1978            
1979             } elsif( LittleORM::Model::Field -> this_is_field( $val ) )
1980             {
1981 0           $dbf_type2 = $val -> db_field_type();
1982 0   0       my $use_ta = ( $val -> table_alias() or $ta );
1983 0 0         if( $val -> model() )
1984             {
1985 0 0         unless( $val -> model() eq $self )
1986             {
1987 0           $use_ta = $val -> determine_ta_for_field_from_another_model( $args -> { '_tables_used' } );
1988             }
1989              
1990             }
1991 0           $val = $val -> form_field_name_for_db_select( $use_ta );
1992             } else
1993             {
1994 0 0         if( LittleORM::Model::Value -> this_is_value( $val ) )
1995             {
1996 0           $dbf_type2 = $val -> db_field_type();
1997             }
1998 0           $val = $self -> __prep_value_for_db_w_field( &__prep_value_for_db( $class_attr, $val ),
1999             $ta,
2000             $args,
2001             $dbh );
2002             }
2003             }
2004              
2005 0           return ( $op, $val, $col, $dbf_type1, $dbf_type2 );
2006             }
2007              
2008             sub __prep_value_for_db_w_field
2009             {
2010 0     0     my ( $self, $v, $ta, $args, $dbh ) = @_;
2011              
2012 0           my $val = $v;
2013              
2014 0 0         if( LittleORM::Model::Field -> this_is_field( $v ) )
    0          
2015             {
2016 0           my $use_ta = $ta;
2017 0 0         if( $v -> model() )
2018             {
2019 0 0         unless( $v -> model() eq $self )
2020             {
2021 0           $use_ta = $v -> determine_ta_for_field_from_another_model( $args -> { '_tables_used' } );
2022             }
2023              
2024             }
2025              
2026 0           $val = $v -> form_field_name_for_db_select( $use_ta );
2027              
2028             } elsif( $dbh )
2029             {
2030 0           $val = &LittleORM::Db::dbq( $v,
2031             $dbh );
2032             }
2033            
2034              
2035 0           return $val;
2036             }
2037              
2038             sub __find_primary_key
2039             {
2040 0     0     my $self = shift;
2041              
2042 0           my @pk = $self -> __find_primary_keys();
2043              
2044 0           return $pk[ 0 ];
2045             }
2046              
2047              
2048             sub __find_primary_keys
2049             {
2050 0     0     my $self = shift;
2051              
2052 0           my @rv = ();
2053              
2054 0           foreach my $attr ( $self -> meta() -> get_all_attributes() )
2055             {
2056 0 0         if( my $pk = &__descr_attr( $attr, 'primary_key' ) )
2057             {
2058 0           push @rv, $attr;
2059             }
2060             }
2061 0           return @rv;
2062             }
2063              
2064             sub __descr_or_undef
2065             {
2066 0     0     my $attr = shift;
2067              
2068 0           my $rv = undef;
2069              
2070 0 0         if( $attr -> can( 'description' ) )
2071             {
2072 0           $rv = $attr -> description();
2073             }
2074            
2075 0           return $rv;
2076             }
2077              
2078             sub __get_db_field_name
2079             {
2080 0     0     my $attr = shift;
2081              
2082 0           assert( $attr );
2083              
2084 0           my $rv = $attr -> name();
2085              
2086 0 0         if( my $t = &__descr_attr( $attr, 'db_field' ) )
2087             {
2088 0           $rv = $t;
2089             }
2090            
2091 0           return $rv;
2092             }
2093              
2094             sub __descr_attr
2095             {
2096 0     0     my $attr = shift;
2097 0           my $attr_attr_name = shift;
2098              
2099 0           my $rv = undef;
2100              
2101 0 0         if( my $d = &__descr_or_undef( $attr ) )
2102             {
2103 0 0         if( my $t = $d -> { $attr_attr_name } )
2104             {
2105 0           $rv = $t;
2106             }
2107             }
2108              
2109 0           return $rv;
2110             }
2111              
2112             42;