| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package ActiveRecord::Simple::Find; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 11 |  |  | 11 |  | 202 | use 5.010; | 
|  | 11 |  |  |  |  | 37 |  | 
| 4 | 11 |  |  | 11 |  | 58 | use strict; | 
|  | 11 |  |  |  |  | 20 |  | 
|  | 11 |  |  |  |  | 220 |  | 
| 5 | 11 |  |  | 11 |  | 49 | use warnings; | 
|  | 11 |  |  |  |  | 20 |  | 
|  | 11 |  |  |  |  | 309 |  | 
| 6 | 11 |  |  | 11 |  | 1210 | use vars qw/$AUTOLOAD/; | 
|  | 11 |  |  |  |  | 23 |  | 
|  | 11 |  |  |  |  | 427 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 11 |  |  | 11 |  | 55 | use Carp; | 
|  | 11 |  |  |  |  | 26 |  | 
|  | 11 |  |  |  |  | 569 |  | 
| 9 | 11 |  |  | 11 |  | 65 | use Storable qw/freeze/; | 
|  | 11 |  |  |  |  | 23 |  | 
|  | 11 |  |  |  |  | 429 |  | 
| 10 | 11 |  |  | 11 |  | 60 | use Module::Load; | 
|  | 11 |  |  |  |  | 28 |  | 
|  | 11 |  |  |  |  | 56 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 11 |  |  | 11 |  | 1880 | use parent 'ActiveRecord::Simple'; | 
|  | 11 |  |  |  |  | 1460 |  | 
|  | 11 |  |  |  |  | 94 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | our $MAXIMUM_LIMIT = 100_000_000_000; | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | sub new { | 
| 19 | 83 |  |  | 83 | 1 | 201 | my ($self_class, $class, @param) = @_; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | #my $self = $class->new(); | 
| 22 | 83 |  |  |  |  | 213 | my $self = bless { class => $class } => $self_class; | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 83 | 50 |  |  |  | 776 | my $table_name = ($self->{class}->can('_get_table_name'))  ? $self->{class}->_get_table_name  : undef; | 
| 25 | 83 | 100 |  |  |  | 344 | my $pkey       = ($self->{class}->can('_get_primary_key')) ? $self->{class}->_get_primary_key : undef; | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 83 |  | 50 |  |  | 403 | $self->{prep_select_fields} //= []; | 
| 28 | 83 |  | 50 |  |  | 305 | $self->{prep_select_from}   //= []; | 
| 29 | 83 |  | 50 |  |  | 296 | $self->{prep_select_where}  //= []; | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 83 |  |  |  |  | 136 | my ($fields, $from, $where); | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 83 | 100 | 100 |  |  | 486 | if (!ref $param[0] && scalar @param == 1) { | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 | 66 |  |  |  |  | 
| 34 | 15 |  |  |  |  | 44 | $fields = qq/"$table_name".*/; | 
| 35 | 15 |  |  |  |  | 29 | $from   = qq/"$table_name"/; | 
| 36 | 15 |  |  |  |  | 35 | $where  = qq/"$table_name"."$pkey" = ?/; | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | $self->{BIND} = \@param | 
| 39 | 15 |  |  |  |  | 60 | } | 
| 40 |  |  |  |  |  |  | elsif (!ref $param[0] && scalar @param == 0) { | 
| 41 | 32 |  |  |  |  | 70 | $fields = qq/"$table_name".*/; | 
| 42 | 32 |  |  |  |  | 57 | $from   = qq/"$table_name"/; | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 32 |  |  |  |  | 53 | $self->{BIND} = undef; | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  | elsif (ref $param[0] && ref $param[0] eq 'HASH') { | 
| 47 |  |  |  |  |  |  | # find many by params | 
| 48 | 26 |  |  |  |  | 74 | my ($bind, $condition_pairs) = $self->parse_hash($param[0]); | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 26 |  |  |  |  | 92 | my $where_str = join q/ AND /, @$condition_pairs; | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 26 |  |  |  |  | 58 | $fields = qq/"$table_name".*/; | 
| 53 | 26 |  |  |  |  | 51 | $from   = qq/"$table_name"/; | 
| 54 | 26 |  |  |  |  | 37 | $where  = $where_str; | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 26 |  |  |  |  | 60 | $self->{BIND} = $bind; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  | elsif (ref $param[0] && ref $param[0] eq 'ARRAY') { | 
| 59 |  |  |  |  |  |  | # find many by primary keys | 
| 60 | 3 |  |  |  |  | 6 | my $whereinstr = join ', ', @{ $param[0] }; | 
|  | 3 |  |  |  |  | 11 |  | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 3 |  |  |  |  | 8 | $fields = qq/"$table_name".*/; | 
| 63 | 3 |  |  |  |  | 11 | $from   = qq/"$table_name"/; | 
| 64 | 3 |  |  |  |  | 9 | $where  = qq/"$table_name"."$pkey" IN ($whereinstr)/; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 3 |  |  |  |  | 6 | $self->{BIND} = undef; | 
| 67 |  |  |  |  |  |  | } | 
| 68 |  |  |  |  |  |  | else { | 
| 69 |  |  |  |  |  |  | # find many by condition | 
| 70 | 7 |  |  |  |  | 17 | my $wherestr = shift @param; | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 7 |  |  |  |  | 19 | $fields = qq/"$table_name".*/; | 
| 73 | 7 |  |  |  |  | 16 | $from   = qq/"$table_name"/; | 
| 74 | 7 |  |  |  |  | 10 | $where  = $wherestr; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 7 |  |  |  |  | 16 | $self->{BIND} = \@param; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 83 | 50 |  |  |  | 179 | push @{ $self->{prep_select_fields} }, $fields if $fields; | 
|  | 83 |  |  |  |  | 193 |  | 
| 80 | 83 | 50 |  |  |  | 165 | push @{ $self->{prep_select_from} }, $from if $from; | 
|  | 83 |  |  |  |  | 143 |  | 
| 81 | 83 | 100 |  |  |  | 149 | push @{ $self->{prep_select_where} }, $where if $where; | 
|  | 51 |  |  |  |  | 94 |  | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 83 |  |  |  |  | 308 | return $self; | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub count { | 
| 87 | 7 |  |  | 7 | 1 | 15 | my $inv = shift; | 
| 88 | 7 | 50 |  |  |  | 24 | my $self = ref $inv ? $inv : $inv->new(@_); | 
| 89 | 7 |  |  |  |  | 21 | $self->{prep_select_fields} = [ 'COUNT(*)' ]; | 
| 90 | 7 | 100 |  |  |  | 15 | if (@{ $self->{prep_group_by} || [] }) { | 
|  | 7 | 100 |  |  |  | 46 |  | 
| 91 | 2 |  |  |  |  | 6 | my $table_name = $self->{class}->_get_table_name; | 
| 92 | 2 |  |  |  |  | 4 | push @{ $self->{prep_select_fields} }, map qq/"$table_name".$_/, @{ $self->{prep_group_by} }; | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 9 |  | 
| 93 | 2 |  |  |  |  | 4 | my @group_by = @{ $self->{prep_group_by} }; | 
|  | 2 |  |  |  |  | 6 |  | 
| 94 | 2 |  |  |  |  | 13 | s/"//g foreach @group_by; | 
| 95 | 2 |  |  |  |  | 4 | my @results; | 
| 96 | 2 |  |  |  |  | 7 | foreach my $item ($self->fetch) { | 
| 97 | 7 |  |  |  |  | 14 | push my @line, (count => $item->{'COUNT(*)'}), map {$_ => $item->$_} @group_by; | 
|  | 7 |  |  |  |  | 15 |  | 
| 98 | 7 |  |  |  |  | 22 | push @results, { @line }; | 
| 99 |  |  |  |  |  |  | } | 
| 100 | 2 |  |  |  |  | 21 | return @results; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  | else { | 
| 103 | 5 |  |  |  |  | 21 | return $self->fetch->{'COUNT(*)'}; | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | sub parse_hash { | 
| 108 | 26 |  |  | 26 | 0 | 58 | my ($self, $param_hash) = @_; | 
| 109 | 26 |  |  |  |  | 44 | my $class = $self->{class}; | 
| 110 | 26 | 50 |  |  |  | 154 | my $table_name = ($self->{class}->can('_get_table_name'))  ? $self->{class}->_get_table_name  : undef; | 
| 111 | 26 |  |  |  |  | 60 | my ($bind, $condition_pairs) = ([],[]); | 
| 112 | 26 |  |  |  |  | 44 | for my $param_name (keys %{ $param_hash }) { | 
|  | 26 |  |  |  |  | 92 |  | 
| 113 | 28 | 50 | 33 |  |  | 109 | if (ref $param_hash->{$param_name} eq 'ARRAY' and !ref $param_hash->{$param_name}[0]) { | 
|  |  | 100 |  |  |  |  |  | 
| 114 | 0 |  |  |  |  | 0 | my $instr = join q/, /, map { '?' } @{ $param_hash->{$param_name} }; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 115 | 0 |  |  |  |  | 0 | push @$condition_pairs, qq/"$table_name"."$param_name" IN ($instr)/; | 
| 116 | 0 |  |  |  |  | 0 | push @$bind, @{ $param_hash->{$param_name} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | elsif (ref $param_hash->{$param_name}) { | 
| 119 | 2 | 50 |  |  |  | 11 | next if !$class->can('_get_relations'); | 
| 120 | 2 | 50 |  |  |  | 7 | my $relation = $class->_get_relations->{$param_name} or next; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 2 | 50 |  |  |  | 6 | next if $relation->{type} ne 'one'; | 
| 123 | 2 |  |  |  |  | 5 | my $fk = $relation->{params}{fk}; | 
| 124 | 2 |  |  |  |  | 5 | my $pk = $relation->{params}{pk}; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 2 | 50 |  |  |  | 6 | if (ref $param_hash->{$param_name} eq __PACKAGE__) { | 
| 127 | 0 |  |  |  |  | 0 | my $object = $param_hash->{$param_name}; | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 0 |  |  |  |  | 0 | my $tmp_table = qq/tmp_table_/ . sprintf("%x", $object); | 
| 130 | 0 |  |  |  |  | 0 | my $request_table = $object->{class}->_get_table_name; | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 0 |  |  |  |  | 0 | $object->{prep_select_fields} = [qq/"$request_table"."$pk"/]; | 
| 133 | 0 |  |  |  |  | 0 | $object->_finish_sql_stmt; | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 0 |  |  |  |  | 0 | push @$condition_pairs, qq/"$table_name"."$fk" IN (SELECT "$tmp_table"."$pk" from ($object->{SQL}) as $tmp_table)/; | 
| 136 | 0 | 0 |  |  |  | 0 | push @$bind, @{ $object->{BIND} } if ref $object->{BIND} eq 'ARRAY'; | 
|  | 0 |  |  |  |  | 0 |  | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  | else { | 
| 139 | 2 |  |  |  |  | 4 | my $object = $param_hash->{$param_name}; | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 2 | 50 |  |  |  | 5 | if (ref $object eq 'ARRAY') { | 
| 142 | 0 |  |  |  |  | 0 | push @$bind, map $_->$pk, @$object; | 
| 143 | 0 |  |  |  |  | 0 | push @$condition_pairs, qq/"$table_name"."$fk" IN (@{[ join ', ', map "?", @$object ]})/; | 
|  | 0 |  |  |  |  | 0 |  | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  | else { | 
| 146 | 2 |  |  |  |  | 9 | push @$condition_pairs, qq/"$table_name"."$fk" = ?/; | 
| 147 | 2 |  |  |  |  | 7 | push @$bind, $object->$pk; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  | else { | 
| 152 | 26 | 50 |  |  |  | 62 | if (defined $param_hash->{$param_name}) { | 
| 153 | 26 |  |  |  |  | 88 | push @$condition_pairs, qq/"$table_name"."$param_name" = ?/; | 
| 154 | 26 |  |  |  |  | 58 | push @$bind, $param_hash->{$param_name}; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | else { | 
| 157 |  |  |  |  |  |  | # is NULL | 
| 158 | 0 |  |  |  |  | 0 | push @$condition_pairs, qq/"$table_name"."$param_name" IS NULL/; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  | } | 
| 162 | 26 |  |  |  |  | 77 | return ($bind, $condition_pairs); | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | sub first { | 
| 166 | 6 |  |  | 6 | 1 | 14 | my ($self, $limit) = @_; | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 6 |  | 100 |  |  | 25 | $limit //= 1; | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 6 | 50 |  |  |  | 23 | $self->{class}->can('_get_primary_key') or croak 'Can\'t use "first" without primary key'; | 
| 171 | 6 |  |  |  |  | 17 | my $primary_key = $self->{class}->_get_primary_key; | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 6 |  |  |  |  | 17 | return $self->order_by($primary_key)->limit($limit)->fetch; | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | sub last { | 
| 177 | 3 |  |  | 3 | 1 | 8 | my ($self, $limit) = @_; | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 3 | 50 |  |  |  | 13 | $self->{class}->can('_get_primary_key') or croak 'Can\'t use "first" without primary key'; | 
| 180 | 3 |  |  |  |  | 9 | my $primary_key = $self->{class}->_get_primary_key; | 
| 181 | 3 |  | 50 |  |  | 14 | $limit //= 1; | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 3 |  |  |  |  | 8 | return $self->order_by($primary_key)->desc->limit($limit)->fetch; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | sub only { | 
| 187 | 8 |  |  | 8 | 1 | 19 | my ($self, @fields) = @_; | 
| 188 |  |  |  |  |  |  |  | 
| 189 | 8 | 50 |  |  |  | 19 | scalar @fields > 0 or croak 'Not defined fields for method "only"'; | 
| 190 | 8 | 50 |  |  |  | 20 | ref $self or croak 'Create an object abstraction before using the modifiers. Use methods like `find`, `first`, `last` at the beginning'; | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 8 | 50 |  |  |  | 31 | if ($self->{class}->can('_get_primary_key')) { | 
| 193 | 8 |  |  |  |  | 21 | my $pk = $self->{class}->_get_primary_key; | 
| 194 | 8 | 100 |  |  |  | 17 | push @fields, $pk if ! grep { $_ eq $pk } @fields; | 
|  | 10 |  |  |  |  | 34 |  | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 8 |  |  |  |  | 21 | my $table_name = $self->{class}->_get_table_name; | 
| 198 | 8 | 100 |  |  |  | 54 | my $mixins = $self->{class}->can('_get_mixins') ? $self->{class}->_get_mixins : undef; | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | my @filtered_prep_select_fields = | 
| 201 | 8 |  |  |  |  | 16 | grep { $_ ne qq/"$table_name".*/ } @{ $self->{prep_select_fields} }; | 
|  | 8 |  |  |  |  | 27 |  | 
|  | 8 |  |  |  |  | 15 |  | 
| 202 | 8 |  |  |  |  | 16 | for my $fld (@fields) { | 
| 203 | 11 | 100 | 100 |  |  | 33 | if ($mixins && grep { $_ eq $fld } keys %$mixins) { | 
|  | 9 |  |  |  |  | 29 |  | 
| 204 | 1 |  |  |  |  | 3 | my $mixin = $mixins->{$fld}->(); | 
| 205 | 1 | 50 |  |  |  | 7 | $mixin .= qq/ AS $fld/ unless $mixin =~ /as\s+\w+$/i; | 
| 206 | 1 |  |  |  |  | 3 | push @filtered_prep_select_fields, $mixin; | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  | else { | 
| 209 | 10 |  |  |  |  | 30 | push @filtered_prep_select_fields, qq/"$table_name"."$fld"/; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 8 |  |  |  |  | 19 | $self->{prep_select_fields} = \@filtered_prep_select_fields; | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 8 |  |  |  |  | 27 | return $self; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | # alias to only: | 
| 219 | 1 |  |  | 1 | 1 | 3 | sub fields { shift->only(@_) } | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | sub order_by { | 
| 222 | 23 |  |  | 23 | 1 | 44 | my ($self, @param) = @_; | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | #return if not defined $self->{SQL}; ### TODO: die | 
| 225 | 23 |  | 100 |  |  | 90 | $self->{prep_order_by} ||= []; | 
| 226 | 23 |  |  |  |  | 27 | push @{$self->{prep_order_by}}, map qq/"$_"/, @param; | 
|  | 23 |  |  |  |  | 89 |  | 
| 227 | 23 |  |  |  |  | 35 | delete $self->{prep_asc_desc}; | 
| 228 |  |  |  |  |  |  |  | 
| 229 | 23 |  |  |  |  | 61 | return $self; | 
| 230 |  |  |  |  |  |  | } | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | sub desc { | 
| 233 | 11 |  |  | 11 | 1 | 23 | return shift->order_by_direction('DESC'); | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | sub asc { | 
| 237 | 2 |  |  | 2 | 1 | 28 | return shift->order_by_direction('ASC'); | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | sub order_by_direction { | 
| 241 | 13 |  |  | 13 | 0 | 23 | my ($self, $direction) = @_; | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | # There are no fields for order yet | 
| 244 | 13 | 50 | 33 |  |  | 35 | return unless ref $self->{prep_order_by} eq 'ARRAY' and scalar @{ $self->{prep_order_by} } > 0; | 
|  | 13 |  |  |  |  | 39 |  | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | # asc/desc is called before: ->asc->desc | 
| 247 | 13 | 50 |  |  |  | 24 | return if defined $self->{prep_asc_desc}; | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | # $direction should be ASC/DESC | 
| 250 | 13 | 50 |  |  |  | 66 | return unless $direction =~ /^(ASC|DESC)$/i; | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | # Add $direction to the latest field | 
| 253 | 13 |  |  |  |  | 21 | @{$self->{prep_order_by}}[-1] .= " $direction"; | 
|  | 13 |  |  |  |  | 31 |  | 
| 254 | 13 |  |  |  |  | 23 | $self->{prep_asc_desc} = 1; | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 13 |  |  |  |  | 34 | return $self; | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | sub group_by { | 
| 260 | 3 |  |  | 3 | 1 | 7 | my ($self, @param) = @_; | 
| 261 |  |  |  |  |  |  |  | 
| 262 | 3 |  | 50 |  |  | 12 | $self->{prep_group_by} ||= []; | 
| 263 | 3 |  |  |  |  | 5 | push @{$self->{prep_group_by}}, map qq/"$_"/, @param; | 
|  | 3 |  |  |  |  | 11 |  | 
| 264 | 3 |  |  |  |  | 10 | return $self; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | sub limit { | 
| 268 | 14 |  |  | 14 | 1 | 27 | my ($self, $limit) = @_; | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | #return if not defined $self->{SQL}; | 
| 271 | 14 | 50 |  |  |  | 29 | return $self if exists $self->{prep_limit}; | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 14 |  |  |  |  | 28 | $self->{prep_limit} = $limit; ### TODO: move $limit to $self->{BIND} | 
| 274 |  |  |  |  |  |  |  | 
| 275 | 14 |  |  |  |  | 34 | return $self; | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | sub offset { | 
| 279 | 5 |  |  | 5 | 1 | 10 | my ($self, $offset) = @_; | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | #return if not defined $self->{SQL}; | 
| 282 | 5 | 50 |  |  |  | 12 | return $self if exists $self->{prep_offset}; | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 5 |  |  |  |  | 8 | $self->{prep_offset} = $offset; ### TODO: move $offset to $self->{BIND} | 
| 285 |  |  |  |  |  |  |  | 
| 286 | 5 |  |  |  |  | 13 | return $self; | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | sub abstract { | 
| 290 | 7 |  |  | 7 | 0 | 13 | my ($self, $opts) = @_; | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 7 | 100 | 66 |  |  | 23 | return $self if ! ref $opts && ref $opts ne 'HASH'; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 5 |  |  |  |  | 18 | while (my ($method, $param) = each %$opts) { | 
| 295 | 9 | 100 |  |  |  | 13 | if ($method eq 'order_by') { | 
| 296 | 4 |  |  |  |  | 6 | $self->order_by(@{ $param->{columns} }); | 
|  | 4 |  |  |  |  | 9 |  | 
| 297 | 4 | 50 |  |  |  | 8 | my $order_direction = (defined $param->{direction}) ? $param->{direction} : undef; | 
| 298 | 4 | 50 |  |  |  | 11 | $self->$order_direction if $order_direction; | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  | else { | 
| 301 | 5 | 100 |  |  |  | 12 | my @p = (ref $param) ? @$param : ($param); | 
| 302 | 5 |  |  |  |  | 12 | $self->$method(@p); | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 5 |  |  |  |  | 8 | return $self; | 
| 307 |  |  |  |  |  |  | } | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | sub select { | 
| 310 | 6 |  |  | 6 | 1 | 16 | my ($self_class, $class, @params) = @_; | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 6 |  |  |  |  | 8 | my @find_params; | 
| 313 |  |  |  |  |  |  | my $abstract_params_hashref; | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 6 |  |  |  |  | 11 | my $first_param = shift @params; | 
| 316 | 6 | 100 |  |  |  | 15 | push @find_params, $first_param if defined $first_param; | 
| 317 |  |  |  |  |  |  |  | 
| 318 | 6 |  |  |  |  | 12 | for my $param (@params) { | 
| 319 |  |  |  |  |  |  | #push @find_params, $param if ref $param ne 'HASH'; | 
| 320 | 5 | 100 |  |  |  | 13 | if (ref $param eq 'HASH') { | 
| 321 | 4 |  |  |  |  | 6 | $abstract_params_hashref = $param; | 
| 322 | 4 |  |  |  |  | 8 | last; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  | else { | 
| 325 | 1 |  |  |  |  | 2 | push @find_params, $param; | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 6 |  |  |  |  | 14 | my $finder = $self_class->new($class, @find_params); | 
| 330 | 6 |  |  |  |  | 14 | $finder->abstract($abstract_params_hashref); | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 6 |  |  |  |  | 12 | return $finder->fetch; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | sub _finish_sql_stmt { | 
| 337 | 82 |  |  | 82 |  | 133 | my ($self) = @_; | 
| 338 |  |  |  |  |  |  |  | 
| 339 | 82 | 50 |  |  |  | 185 | ref $self->{prep_select_fields} or croak 'Invalid prepare SQL statement'; | 
| 340 | 82 | 50 |  |  |  | 159 | ref $self->{prep_select_from}   or croak 'Invalid prepare SQL statement'; | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 82 |  |  |  |  | 208 | my $table_name = $self->{class}->_get_table_name; | 
| 343 | 82 | 100 |  |  |  | 139 | my @add = grep { $_ !~~ $self->{prep_select_fields} } map qq/"$table_name".$_/, @{ $self->{prep_group_by}||[] }; | 
|  | 4 |  |  |  |  | 58 |  | 
|  | 82 |  |  |  |  | 307 |  | 
| 344 | 82 |  |  |  |  | 129 | push @{ $self->{prep_select_fields} }, @add; | 
|  | 82 |  |  |  |  | 160 |  | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 82 |  |  |  |  | 119 | $self->{SQL} = "SELECT " . (join q/, /, @{ $self->{prep_select_fields} }) . "\n"; | 
|  | 82 |  |  |  |  | 295 |  | 
| 347 | 82 |  |  |  |  | 168 | $self->{SQL} .= "FROM " . (join q/, /, @{ $self->{prep_select_from} }) . "\n"; | 
|  | 82 |  |  |  |  | 223 |  | 
| 348 |  |  |  |  |  |  |  | 
| 349 | 82 | 100 |  |  |  | 220 | if (defined $self->{prep_left_joins}) { | 
| 350 | 7 |  |  |  |  | 14 | $self->{SQL} .= "$_\n" for @{ $self->{prep_left_joins} }; | 
|  | 7 |  |  |  |  | 36 |  | 
| 351 | 7 |  |  |  |  | 25 | $self->{has_joined_table} = 1; | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 82 | 50 |  |  |  | 134 | if (@{ $self->{prep_select_where}||[] }) { | 
|  | 82 | 100 |  |  |  | 232 |  | 
| 355 | 52 |  |  |  |  | 99 | $self->{SQL} .= "WHERE\n"; | 
| 356 | 52 |  |  |  |  | 82 | $self->{SQL} .= join " AND ", @{ $self->{prep_select_where} }; | 
|  | 52 |  |  |  |  | 128 |  | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  |  | 
| 359 | 82 | 100 |  |  |  | 123 | if (@{ $self->{prep_group_by}||[] }) { | 
|  | 82 | 100 |  |  |  | 292 |  | 
| 360 | 3 |  |  |  |  | 7 | $self->{SQL} .= ' GROUP BY '; | 
| 361 | 3 |  |  |  |  | 5 | $self->{SQL} .= join q/, /, @{ $self->{prep_group_by} }; | 
|  | 3 |  |  |  |  | 7 |  | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 82 | 100 |  |  |  | 112 | if (@{ $self->{prep_order_by}||[] }) { | 
|  | 82 | 100 |  |  |  | 265 |  | 
| 365 | 24 |  |  |  |  | 41 | $self->{SQL} .= ' ORDER BY '; | 
| 366 | 24 |  |  |  |  | 32 | $self->{SQL} .= join q/, /, @{ $self->{prep_order_by} }; | 
|  | 24 |  |  |  |  | 42 |  | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 82 |  | 66 |  |  | 327 | $self->{SQL} .= ' LIMIT ' .  ($self->{prep_limit}  // $MAXIMUM_LIMIT); | 
| 370 | 82 |  | 100 |  |  | 267 | $self->{SQL} .= ' OFFSET '.  ($self->{prep_offset} // 0); | 
| 371 |  |  |  |  |  |  |  | 
| 372 | 82 |  |  |  |  | 167 | return $self; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | sub _finish_object_representation { | 
| 376 | 130 |  |  | 130 |  | 243 | my ($self, $obj, $object_data, $read_only) = @_; | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 130 | 100 |  |  |  | 272 | if ($self->{has_joined_table}) { | 
| 379 |  |  |  |  |  |  | RELATION: | 
| 380 | 14 |  |  |  |  | 23 | for my $rel_name (@{ $self->{with} }) { | 
|  | 14 |  |  |  |  | 33 |  | 
| 381 | 0 | 0 |  |  |  | 0 | my $relation = $self->{class}->_get_relations->{$rel_name} or next RELATION; | 
| 382 | 0 |  |  |  |  | 0 | my %pairs = map { $_, $object_data->{$_} } grep { $_ =~ /^JOINED\_$rel_name\_/ } keys %$object_data; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 383 | 0 | 0 |  |  |  | 0 | next RELATION unless %pairs; | 
| 384 |  |  |  |  |  |  |  | 
| 385 | 0 |  |  |  |  | 0 | for my $key (keys %pairs) { | 
| 386 | 0 |  |  |  |  | 0 | my $val = delete $pairs{$key}; | 
| 387 | 0 |  |  |  |  | 0 | $key =~ s/^JOINED\_$rel_name\_//; | 
| 388 | 0 |  |  |  |  | 0 | $pairs{$key} = $val; | 
| 389 |  |  |  |  |  |  | } | 
| 390 | 0 |  |  |  |  | 0 | $obj->{"relation_instance_$rel_name"} = $relation->{class}->new(\%pairs); | 
| 391 |  |  |  |  |  |  | #bless \%pairs, $relation->{class}; | 
| 392 |  |  |  |  |  |  |  | 
| 393 | 0 |  |  |  |  | 0 | $obj->_delete_keys(qr/^JOINED\_$rel_name/); | 
| 394 |  |  |  |  |  |  | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | } | 
| 397 |  |  |  |  |  |  |  | 
| 398 | 130 | 50 |  |  |  | 244 | $obj->{read_only} = 1 if defined $read_only; | 
| 399 | 130 | 100 | 66 |  |  | 464 | $obj->{snapshoot} = freeze($object_data) if $obj->can('_smart_saving_used') && $obj->_smart_saving_used; | 
| 400 | 130 |  |  |  |  | 345 | $obj->{isin_database} = 1; | 
| 401 |  |  |  |  |  |  |  | 
| 402 | 130 |  |  |  |  | 188 | return $obj; | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | sub fetch { | 
| 406 | 76 |  |  | 76 | 1 | 163 | my ($self, $param) = @_; | 
| 407 |  |  |  |  |  |  |  | 
| 408 | 76 |  |  |  |  | 115 | my ($read_only, $limit); | 
| 409 | 76 | 50 |  |  |  | 191 | if (ref $param eq 'HASH') { | 
| 410 | 0 |  |  |  |  | 0 | $limit     = $param->{limit}; | 
| 411 | 0 |  |  |  |  | 0 | $read_only = $param->{read_only}; | 
| 412 |  |  |  |  |  |  | } | 
| 413 |  |  |  |  |  |  | else { | 
| 414 | 76 |  |  |  |  | 111 | $limit = $param; | 
| 415 |  |  |  |  |  |  | } | 
| 416 |  |  |  |  |  |  |  | 
| 417 | 76 | 50 |  |  |  | 155 | return $self->_get_slice($limit) if $self->{_objects}; | 
| 418 |  |  |  |  |  |  |  | 
| 419 | 76 |  |  |  |  | 196 | $self->_finish_sql_stmt(); | 
| 420 | 76 |  |  |  |  | 208 | $self->_quote_sql_stmt(); | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 76 |  |  |  |  | 121 | my $class = $self->{class}; | 
| 423 | 76 | 50 |  |  |  | 176 | my $sth = $self->dbh->prepare($self->{SQL}) or croak $self->dbh->errstr; | 
| 424 | 76 | 50 |  |  |  | 5018 | $sth->execute(@{ $self->{BIND} }) or croak $self->dbh->errstr; | 
|  | 76 |  |  |  |  | 1845 |  | 
| 425 | 76 | 100 |  |  |  | 241 | if (wantarray) { | 
| 426 | 29 |  |  |  |  | 47 | my @objects; | 
| 427 | 29 |  |  |  |  | 47 | my $i = 0; | 
| 428 | 29 |  |  |  |  | 628 | while (my $object_data = $sth->fetchrow_hashref()) { | 
| 429 | 83 |  |  |  |  | 191 | $i++; | 
| 430 | 83 |  |  |  |  | 246 | my $obj = $class->new($object_data); | 
| 431 | 83 |  |  |  |  | 201 | $self->_finish_object_representation($obj, $object_data, $read_only); | 
| 432 | 83 |  |  |  |  | 129 | push @objects, $obj; | 
| 433 |  |  |  |  |  |  |  | 
| 434 | 83 | 50 | 33 |  |  | 1321 | last if $limit && $i == $limit; | 
| 435 |  |  |  |  |  |  | } | 
| 436 | 29 |  |  |  |  | 81 | delete $self->{has_joined_table}; | 
| 437 |  |  |  |  |  |  |  | 
| 438 | 29 |  |  |  |  | 410 | return @objects; | 
| 439 |  |  |  |  |  |  | } | 
| 440 |  |  |  |  |  |  | else { | 
| 441 | 47 | 50 |  |  |  | 678 | my $object_data = $sth->fetchrow_hashref() or return; | 
| 442 | 47 |  |  |  |  | 234 | my $obj = $class->new($object_data); | 
| 443 | 47 |  |  |  |  | 143 | $self->_finish_object_representation($obj, $object_data, $read_only); | 
| 444 | 47 |  |  |  |  | 73 | delete $self->{has_joined_table}; | 
| 445 |  |  |  |  |  |  |  | 
| 446 | 47 |  |  |  |  | 648 | return $obj; | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  | } | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | sub upload { | 
| 451 | 1 |  |  | 1 | 1 | 6 | my ($self, $param) = @_; | 
| 452 |  |  |  |  |  |  |  | 
| 453 | 1 |  |  |  |  | 13 | my $o = $self->fetch($param); | 
| 454 | 1 |  |  |  |  | 3 | $_[0] = $o; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 1 |  |  |  |  | 6 | return $_[0]; | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | sub next { | 
| 460 | 7 |  |  | 7 | 0 | 1979 | my ($self, $n) = @_; | 
| 461 |  |  |  |  |  |  |  | 
| 462 | 7 |  | 100 |  |  | 26 | $n ||= 1; | 
| 463 |  |  |  |  |  |  |  | 
| 464 | 7 |  |  |  |  | 10 | $self->{prep_limit} = $n; | 
| 465 | 7 | 100 |  |  |  | 16 | $self->{prep_offset} = 0 unless defined $self->{prep_offset}; | 
| 466 | 7 |  |  |  |  | 14 | my @result = $self->fetch; | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 7 |  |  |  |  | 15 | $self->{prep_offset} += $n; | 
| 469 |  |  |  |  |  |  |  | 
| 470 | 7 | 100 |  |  |  | 25 | return wantarray ? @result : $result[0]; | 
| 471 |  |  |  |  |  |  | } | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | sub with { | 
| 474 | 0 |  |  | 0 | 1 | 0 | my ($self, @rels) = @_; | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 0 | 0 |  |  |  | 0 | return $self if exists $self->{prep_left_joins}; | 
| 477 | 0 | 0 |  |  |  | 0 | return $self unless @rels; | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 0 | 0 |  |  |  | 0 | $self->{class}->can('_get_relations') | 
| 480 |  |  |  |  |  |  | or die "Class doesn't have any relations"; | 
| 481 |  |  |  |  |  |  |  | 
| 482 | 0 |  |  |  |  | 0 | my $table_name = $self->{class}->_get_table_name; | 
| 483 |  |  |  |  |  |  |  | 
| 484 | 0 |  |  |  |  | 0 | $self->{prep_left_joins} = []; | 
| 485 | 0 |  |  |  |  | 0 | $self->{with} = \@rels; | 
| 486 |  |  |  |  |  |  | RELATION: | 
| 487 | 0 |  |  |  |  | 0 | for my $rel_name (@rels) { | 
| 488 | 0 | 0 |  |  |  | 0 | my $relation = $self->{class}->_get_relations->{$rel_name} | 
| 489 |  |  |  |  |  |  | or next RELATION; | 
| 490 |  |  |  |  |  |  |  | 
| 491 | 0 | 0 |  |  |  | 0 | next RELATION unless grep { $_ eq $relation->{type} } qw/one only/; | 
|  | 0 |  |  |  |  | 0 |  | 
| 492 | 0 |  |  |  |  | 0 | my $rel_table_name = $relation->{class}->_get_table_name; | 
| 493 |  |  |  |  |  |  |  | 
| 494 | 0 |  |  |  |  | 0 | my $rel_columns = $relation->{class}->_get_columns; | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | #push @{ $self->{prep_select_fields} }, qq/"$rel_table_name".*/; | 
| 497 | 0 |  |  |  |  | 0 | push @{ $self->{prep_select_fields} }, | 
| 498 | 0 |  |  |  |  | 0 | map { qq/"$rel_table_name"."$_" AS "JOINED_$rel_name\_$_"/  } | 
| 499 | 0 |  |  |  |  | 0 | @{ $relation->{class}->_get_columns }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 0 | 0 |  |  |  | 0 | if ($relation->{type} eq 'one') { | 
| 502 | 0 |  |  |  |  | 0 | my $join_sql = qq/LEFT JOIN "$rel_table_name" ON /; | 
| 503 | 0 |  |  |  |  | 0 | $join_sql .= qq/"$rel_table_name"."$relation->{params}{pk}"/; | 
| 504 | 0 |  |  |  |  | 0 | $join_sql .= qq/ = "$table_name"."$relation->{params}{fk}"/; | 
| 505 |  |  |  |  |  |  |  | 
| 506 | 0 |  |  |  |  | 0 | push @{ $self->{prep_left_joins} }, $join_sql; | 
|  | 0 |  |  |  |  | 0 |  | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  | } | 
| 509 |  |  |  |  |  |  |  | 
| 510 | 0 |  |  |  |  | 0 | return $self; | 
| 511 |  |  |  |  |  |  | } | 
| 512 |  |  |  |  |  |  |  | 
| 513 | 0 |  |  | 0 | 1 | 0 | sub left_join { shift->with(@_) } | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | sub to_sql { | 
| 516 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 517 |  |  |  |  |  |  |  | 
| 518 | 0 |  |  |  |  | 0 | $self->_finish_sql_stmt(); | 
| 519 | 0 |  |  |  |  | 0 | $self->_quote_sql_stmt(); | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 0 | 0 |  |  |  | 0 | return wantarray ? ($self->{SQL}, $self->{BIND}) : $self->{SQL}; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | sub exists { | 
| 525 | 6 |  |  | 6 | 1 | 13 | my ($self) = @_; | 
| 526 |  |  |  |  |  |  |  | 
| 527 | 6 |  |  |  |  | 18 | $self->{prep_select_fields} = ['1']; | 
| 528 | 6 |  |  |  |  | 22 | $self->_finish_sql_stmt; | 
| 529 | 6 |  |  |  |  | 59 | $self->_quote_sql_stmt; | 
| 530 |  |  |  |  |  |  |  | 
| 531 | 6 |  |  |  |  | 46 | my $sth = $self->dbh->prepare($self->{SQL}); | 
| 532 | 6 |  |  |  |  | 531 | $sth->execute(@{ $self->{BIND} }); | 
|  | 6 |  |  |  |  | 128 |  | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 6 |  |  |  |  | 123 | return $sth->fetchrow_arrayref(); | 
| 535 |  |  |  |  |  |  | } | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | ### Private | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | sub _find_many_to_many { | 
| 541 | 7 |  |  | 7 |  | 18 | my ($self_class, $class, $param) = @_; | 
| 542 |  |  |  |  |  |  |  | 
| 543 | 7 | 50 | 33 |  |  | 23 | return unless $self_class->dbh && $class && $param; | 
|  |  |  | 33 |  |  |  |  | 
| 544 |  |  |  |  |  |  |  | 
| 545 | 7 |  |  |  |  | 13 | my $mc_fkey; | 
| 546 | 7 |  |  |  |  | 13 | my $class_opts = {}; | 
| 547 | 7 |  |  |  |  | 14 | my $root_class_opts = {}; | 
| 548 |  |  |  |  |  |  |  | 
| 549 | 7 |  |  |  |  | 14 | eval { load $param->{m_class} }; | 
|  | 7 |  |  |  |  | 26 |  | 
| 550 |  |  |  |  |  |  |  | 
| 551 | 7 |  |  |  |  | 1511 | for my $opts ( values %{ $param->{m_class}->_get_relations } ) { | 
|  | 7 |  |  |  |  | 37 |  | 
| 552 | 14 | 100 |  |  |  | 52 | if ($opts->{class} eq $param->{root_class}) { | 
|  |  | 50 |  |  |  |  |  | 
| 553 | 7 |  |  |  |  | 13 | $root_class_opts = $opts; | 
| 554 |  |  |  |  |  |  | } | 
| 555 |  |  |  |  |  |  | elsif ($opts->{class} eq $class) { | 
| 556 | 7 |  |  |  |  | 17 | $class_opts = $opts; | 
| 557 |  |  |  |  |  |  | } | 
| 558 |  |  |  |  |  |  | } | 
| 559 |  |  |  |  |  |  |  | 
| 560 | 7 |  |  |  |  | 15 | my $self = $self_class->new($class, @{ $param->{where_statement} }); | 
|  | 7 |  |  |  |  | 30 |  | 
| 561 |  |  |  |  |  |  |  | 
| 562 | 7 |  |  |  |  | 21 | my $connected_table_name = $class->_get_table_name; | 
| 563 | 7 |  |  |  |  | 26 | $self->{prep_select_from} = [ $param->{m_class}->_get_table_name ]; | 
| 564 |  |  |  |  |  |  |  | 
| 565 | 7 |  |  |  |  | 41 | push @{ $self->{prep_left_joins} }, | 
| 566 |  |  |  |  |  |  | 'JOIN ' . $connected_table_name . ' ON ' . $connected_table_name . '.' . $class->_get_primary_key . ' = ' | 
| 567 | 7 |  |  |  |  | 15 | . $param->{m_class}->_get_table_name . '.' . $class_opts->{params}{fk}; | 
| 568 |  |  |  |  |  |  |  | 
| 569 | 7 |  |  |  |  | 36 | push @{ $self->{prep_select_where} }, | 
| 570 | 7 |  |  |  |  | 13 | $root_class_opts->{params}{fk} . ' = ' . $param->{self}->{ $param->{root_class}->_get_primary_key }; | 
| 571 |  |  |  |  |  |  |  | 
| 572 | 7 |  |  |  |  | 55 | return $self; | 
| 573 |  |  |  |  |  |  | } | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | sub _get_slice { | 
| 576 | 0 |  |  | 0 |  | 0 | my ($self, $time) = @_; | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | return unless $self->{_objects} | 
| 579 |  |  |  |  |  |  | && ref $self->{_objects} eq 'ARRAY' | 
| 580 | 0 | 0 | 0 |  |  | 0 | && scalar @{ $self->{_objects} } > 0; | 
|  | 0 |  | 0 |  |  | 0 |  | 
| 581 |  |  |  |  |  |  |  | 
| 582 | 0 | 0 |  |  |  | 0 | if (wantarray) { | 
| 583 | 0 |  | 0 |  |  | 0 | $time ||= scalar @{ $self->{_objects} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 584 | 0 |  |  |  |  | 0 | return splice @{ $self->{_objects} }, 0, $time; | 
|  | 0 |  |  |  |  | 0 |  | 
| 585 |  |  |  |  |  |  | } | 
| 586 |  |  |  |  |  |  | else { | 
| 587 | 0 |  |  |  |  | 0 | return shift @{ $self->{_objects} }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 588 |  |  |  |  |  |  | } | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | sub _quote_sql_stmt { | 
| 592 | 82 |  |  | 82 |  | 136 | my ($self) = @_; | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 82 | 50 | 33 |  |  | 301 | return unless $self->{SQL} && $self->dbh; | 
| 595 |  |  |  |  |  |  |  | 
| 596 | 82 |  |  |  |  | 235 | my $driver_name = $self->dbh->{Driver}{Name}; | 
| 597 | 82 |  | 50 |  |  | 289 | $driver_name //= 'Pg'; | 
| 598 | 82 |  |  |  |  | 245 | my $quotes_map = { | 
| 599 |  |  |  |  |  |  | Pg => q/"/, | 
| 600 |  |  |  |  |  |  | mysql => q/`/, | 
| 601 |  |  |  |  |  |  | SQLite => q/`/, | 
| 602 |  |  |  |  |  |  | }; | 
| 603 | 82 |  |  |  |  | 151 | my $quote = $quotes_map->{$driver_name}; | 
| 604 |  |  |  |  |  |  |  | 
| 605 | 82 |  |  |  |  | 467 | $self->{SQL} =~ s/"/$quote/g; | 
| 606 |  |  |  |  |  |  |  | 
| 607 | 82 |  |  |  |  | 232 | return $self; | 
| 608 |  |  |  |  |  |  | } | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  | 0 |  |  | sub DESTROY { } | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | sub AUTOLOAD { | 
| 613 | 0 |  |  | 0 |  |  | my $call = $AUTOLOAD; | 
| 614 | 0 |  |  |  |  |  | my $self = shift; | 
| 615 | 0 |  |  |  |  |  | my $class = ref $self; | 
| 616 |  |  |  |  |  |  |  | 
| 617 | 0 |  |  |  |  |  | $call =~ s/.*:://; | 
| 618 | 0 |  |  |  |  |  | my $error = "Can't call method `$call` on class $class.\nPerhaps you have forgotten to fetch your object?"; | 
| 619 |  |  |  |  |  |  |  | 
| 620 | 0 |  |  |  |  |  | croak $error; | 
| 621 |  |  |  |  |  |  | } | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | 1; | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  |  |