File Coverage

blib/lib/Data/Model/Schema/Properties.pm
Criterion Covered Total %
statement 241 246 97.9
branch 89 106 83.9
condition 49 76 64.4
subroutine 37 37 100.0
pod 0 19 0.0
total 416 484 85.9


line stmt bran cond sub pod time code
1             package Data::Model::Schema::Properties;
2 73     73   231276 use strict;
  73         145  
  73         2397  
3 73     73   551 use warnings;
  73         141  
  73         2086  
4 73     73   751 use base qw(Data::Model::Accessor);
  73         144  
  73         26669  
5              
6 73     73   388 use Carp ();
  73         136  
  73         2852  
7             $Carp::Internal{(__PACKAGE__)}++;
8              
9 73     73   62269 use Class::Trigger qw( pre_insert pre_save post_save post_load pre_update pre_inflate post_inflate pre_deflate post_deflate );
  73         107252  
  73         643  
10 73     73   7786 use Encode ();
  73         22572  
  73         2041  
11 73     73   2031 use Params::Validate ':all';
  73         25705  
  73         19509  
12              
13 73     73   1747 use Data::Model::Schema;
  73         137  
  73         2044  
14 73     73   48267 use Data::Model::Schema::Inflate;
  73         203  
  73         549  
15 73     73   45718 use Data::Model::Schema::SQL;
  73         372  
  73         16291  
16              
17             __PACKAGE__->mk_accessors(qw/ driver schema_class model class column columns index unique key options has_inflate has_deflate alias_column aluas_column_revers_map /);
18              
19              
20             our @RESERVED = qw(
21             update save new
22             add_trigger call_trigger remove_trigger
23             );
24              
25              
26             sub new {
27 179     179 0 1952 my($class, %args) = @_;
28 179         3103 bless { %args }, $class;
29             }
30              
31             sub new_obj {
32 1556     1556 0 3504 my $self = shift;
33 1556         15156 $self->{class}->new(@_);
34             }
35              
36             sub has_index {
37 112 100   112 0 2416 $_[0]->{unique}->{$_[1]} || $_[0]->{index}->{$_[1]}
38             }
39              
40             sub add_keys {
41 158     158 0 387 my($self, $key, %args) = @_;
42 158 100       982 $self->{key} = ref($key) eq 'ARRAY' ? $key : [ $key ];
43             }
44              
45             BEGIN {
46 73     73   243 for my $name (qw/ unique index /) {
47 73     73   643 no strict 'refs';
  73         144  
  73         10709  
48 146         223499 *{"add_$name"} = sub {
49 60     60   140 my($self, $index, $columns, %args) = @_;
        49      
50 60   66     305 my $key = $columns || $index;
51 60 50 33     432 Carp::croak sprintf '%s::%s : %s name is require', $self->schema_class, $self->name, $name
52             if ref($index) || !defined $index;
53 60 100       350 $key = [ $key ] unless ref($key) eq 'ARRAY';
54 60         278 $self->{$name}->{$index} = $key;
55 146         702 };
56             }
57             }
58              
59             sub add_column {
60 510     510 0 738 my $self = shift;
61 510         821 my($column, $type, $options) = @_;
62 510 100       1670 return $self->add_column_sugar(@_) if $column =~ /^[^\.+]+\.[^\.+]+$/;
63 2544         5312 Carp::croak "Column can't be called '$column': reserved name"
64 424 50       714 if grep { lc $_ eq lc $column } @RESERVED;
65              
66 424 50 66     1360 Carp::croak 'The multiplex definition of "require" and the "required" is carried out.'
67             if exists $options->{require} && exists $options->{required};
68 424 100       1035 if (exists $options->{require}) {
69 14         39 $options->{required} = delete $options->{require};
70             }
71              
72             # validation for $options
73 424 100       1044 if ($Data::Model::RUN_VALIDATION) {
74 421         490 my @p = %{ $options };
  421         1209  
75 421         32346 validate(
76             @p, {
77             size => {
78             type => SCALAR,
79             regex => qr/\A[0-9]+\z/,
80             optional => 1,
81             },
82             required => {
83             type => BOOLEAN,
84             optional => 1,
85             },
86             null => {
87             type => BOOLEAN,
88             optional => 1,
89             },
90             signed => {
91             type => BOOLEAN,
92             optional => 1,
93             },
94             unsigned => {
95             type => BOOLEAN,
96             optional => 1,
97             },
98             decimals => {
99             type => BOOLEAN,
100             optional => 1,
101             },
102             zerofill => {
103             type => BOOLEAN,
104             optional => 1,
105             },
106             binary => {
107             type => BOOLEAN,
108             optional => 1,
109             },
110             ascii => {
111             type => BOOLEAN,
112             optional => 1,
113             },
114             unicode => {
115             type => BOOLEAN,
116             optional => 1,
117             },
118             default => {
119             type => SCALAR | CODEREF,
120             optional => 1,
121             },
122             # validation => {},
123             auto_increment => {
124             type => BOOLEAN,
125             optional => 1,
126             },
127             inflate => {
128             type => SCALAR | CODEREF,
129             optional => 1,
130             },
131             deflate => {
132             type => SCALAR | CODEREF,
133             optional => 1,
134             },
135             }
136             );
137             }
138              
139 416 100       7719 $self->{utf8_columns}->{$column} = 1
140             if delete $self->{_build_tmp}->{utf8_column}->{$column};
141              
142 416         737 push @{ $self->{columns} }, $column;
  416         934  
143 416   100     3637 $self->{column}->{$column} = +{
      50        
144             type => $type || 'char',
145             options => $options || +{},
146             };
147             }
148             sub add_utf8_column {
149 36     36 0 54 my $self = shift;
150 36         55 my($column) = @_;
151              
152 36   100     130 $self->{_build_tmp}->{utf8_column} ||= {};
153 36         114 $self->{_build_tmp}->{utf8_column}->{$column} = 1;
154 36         89 $self->add_column(@_);
155             }
156              
157             sub add_alias_column {
158 52     52 0 68 my $self = shift;
159 52         89 my($base_name, $alias_name, $args) = @_;
160 52   50     293 $self->{aluas_column_revers_map}->{$base_name} ||= [];
161 52         63 push @{ $self->{aluas_column_revers_map}->{$base_name} }, $alias_name;
  52         127  
162 52 100       465 $self->{alias_column}->{$alias_name} = +{
163 52         63 %{ $args || {} },
164             base => $base_name,
165             };
166             }
167              
168             sub add_column_sugar {
169 86     86 0 145 my $self = shift;
170 86         114 my $name = shift;
171 86         298 my $sugar = Data::Model::Schema->get_column_sugar($self);
172 86 50 33     517 Carp::croak "Undefined column of '$name'"
173             unless exists $sugar->{$name} && $sugar->{$name};
174              
175 86         139 my $conf = $sugar->{$name};
176 86         398 my %clone = (
177             type => $conf->{type},
178 86         138 options => +{ %{ $conf->{options} } },
179             );
180 86         131 my $column;
181 86 100 100     371 if (@_ == 0 || ref($_[0])) {
182 65         81 my $model;
183 65         202 ($model, $column) = split /\./, $name;
184 65 100       220 unless ($self->{model} eq $model) {
185 1         5 $column = join '_', $model, $column;
186             }
187             } else {
188 21         42 $column = shift;
189             }
190 86 100 66     269 if (@_ && ref($_[0]) eq 'HASH') {
191 7         12 $clone{options} = +{ %{ $clone{options} }, %{ ( shift ) } }
  7         21  
  7         25  
192             }
193 86 100       290 if (my $alias_args = delete $clone{options}->{alias}) {
194 28   100     128 my $rename_map = delete $clone{options}->{alias_rename} || {};
195 28         41 while (my($alias_name, $args) = each %{ $alias_args }) {
  56         205  
196 28   66     134 $self->add_alias_column($column, $rename_map->{$alias_name} || $alias_name, $args);
197             }
198             }
199              
200 86 100       307 $self->{utf8_columns}->{$column} = 1
201             if delete $self->{_build_tmp}->{utf8_column}->{$name};
202              
203 86         307 $self->add_column($column, $clone{type}, $clone{options});
204             }
205              
206             sub add_options {
207 16     16 0 41 my $self = shift;
208 16 50       87 if (ref($_[0]) eq 'HASH') {
    50          
209 0         0 $self->{options} = shift;
210             } elsif (!(@_ % 2)) {
211 16         65 while (my($key, $value) = splice @_, 0, 2) {
212 16         101 $self->{options}->{$key} = $value;
213             }
214             }
215             }
216              
217             sub column_names {
218 552     552 0 1800 my $self = shift;
219 552         1051 @{ $self->{columns} };
  552         4523  
220             }
221              
222             sub column_type {
223 1430     1430 0 2820 my($self, $column) = @_;
224 1430 50 33     16513 return 'char' unless $column && $self->{column}->{$column} && $self->{column}->{$column}->{type};
      33        
225 1430         6686 $self->{column}->{$column}->{type};
226             }
227             sub column_options {
228 769     769 0 1796 my($self, $column) = @_;
229 769 50       10234 $self->{column}->{$column}->{options} || +{};
230             }
231              
232             sub setup_inflate {
233 167     167 0 295 my $self = shift;
234              
235 167         387 $self->{inflate_columns} = [];
236 167         344 $self->{deflate_columns} = [];
237              
238 167         293 while (my($column, $data) = each %{ $self->{column} }) {
  580         1968  
239 413         642 my $opts = $data->{options};
240              
241 413         554 my $inflate = $opts->{inflate};
242 413 100 100     1241 if ($inflate && ref($inflate) ne 'CODE') {
243 8         38 $opts->{inflate} = Data::Model::Schema::Inflate->get_inflate($inflate);
244 8         14 $opts->{deflate} = $inflate;
245 8         14 $inflate = $opts->{inflate};
246             }
247 413 100       925 if (ref($inflate) eq 'CODE') {
248 24         35 push @{ $self->{inflate_columns} }, $column;
  24         51  
249 24         45 $self->{has_inflate} = 1;
250             } else {
251 389         598 delete $opts->{inflate};
252             }
253              
254 413         558 my $deflate = $opts->{deflate};
255 413 100 100     1271 if ($deflate && ref($deflate) ne 'CODE') {
256 8         31 $opts->{deflate} = Data::Model::Schema::Inflate->get_deflate($deflate);
257 8         13 $deflate = $opts->{deflate};
258             }
259 413 100       788 if (ref($deflate) eq 'CODE') {
260 32         53 push @{ $self->{deflate_columns} }, $column;
  32         79  
261 32         105 $self->{has_deflate} = 1;
262             } else {
263 381         850 delete $opts->{deflate};
264             }
265             }
266              
267 167 100       272 if (scalar(%{ $self->{utf8_columns} })) {
  167         570  
268 28         58 $self->{has_inflate} = $self->{has_deflate} = 1;
269 28         38 my @columns = keys %{ $self->{column} };
  28         98  
270 28         60 $self->{inflate_columns} = \@columns;
271 28         62 $self->{deflate_columns} = \@columns;
272             }
273              
274             # for alias
275 167         394 while (my($base, $list) = each %{ $self->{aluas_column_revers_map} }) {
  219         1185  
276 52         96 for my $alias (@{ $list }) {
  52         102  
277 52         99 my $args = $self->{alias_column}->{$alias};
278 52         91 my $inflate = $args->{inflate};
279              
280 52 100 100     263 if ($inflate && ref($inflate) ne 'CODE') {
281 16         156 $args->{inflate} = Data::Model::Schema::Inflate->get_inflate($inflate);
282 16         81 $args->{deflate} = Data::Model::Schema::Inflate->get_deflate($inflate);
283             }
284              
285 52         92 my $inflate_code = $args->{inflate};
286 52         80 my $is_utf8 = $args->{is_utf8};
287 52   50     219 my $charset = $args->{charset} || 'utf8';
288              
289             # make inflate2alias
290 52         68 my $code;
291              
292 52 100 100     296 if ($is_utf8 && $inflate_code) {
    100          
    100          
293             $code = sub {
294 72     72   649 $_[0]->{alias_values}->{$alias} = $inflate_code->( Encode::decode( $charset, $_[0]->{column_values}->{$base} ) );
295 16         79 };
296             } elsif ($is_utf8) {
297             $code = sub {
298 48     48   323 $_[0]->{alias_values}->{$alias} = Encode::decode( $charset, $_[0]->{column_values}->{$base} );
299 8         45 };
300             } elsif ($inflate_code) {
301             $code = sub {
302 108     108   558 $_[0]->{alias_values}->{$alias} = $inflate_code->( $_[0]->{column_values}->{$base} );
303 20         95 };
304             } else {
305             $code = sub {
306 48     48   422 $_[0]->{alias_values}->{$alias} = $_[0]->{column_values}->{$base};
307 8         43 };
308             }
309 52         227 $args->{inflate2alias} = $code;
310             }
311             }
312             }
313              
314             sub inflate {
315 1556 100   1556 0 8243 if ($_[0]->{has_inflate}) {
316 104         202 my($self, $columns) = @_;
317 104         172 my $orig_columns;
318 104 50       555 if (ref($columns) eq $self->{class}) {
    0          
319 104         282 $orig_columns = $columns;
320 104         597 $columns = $columns->{column_values};
321             } elsif (ref($columns) ne 'HASH') {
322 0         0 Carp::croak "required types 'HASH' or '$self->{class}' of inflate";
323             }
324 104         518 $self->call_trigger('pre_inflate', $columns, $orig_columns);
325              
326 104         5082 for my $column (@{ $self->{inflate_columns} }) {
  104         333  
327 240 50       781 next unless defined $columns->{$column};
328              
329 240         575 my $opts = $self->{column}->{$column}->{options};
330 240         406 my $val = $columns->{$column};
331              
332 240 100       716 if ($self->{utf8_columns}->{$column}) {
333 116   50     530 my $charset = $opts->{charset} || 'utf8';
334 116         547 $val = Encode::decode($charset, $val);
335             }
336              
337 240 100       5946 $val = $opts->{inflate}->($val) if ref($opts->{inflate}) eq 'CODE';
338              
339 240 100 33     4193 $orig_columns->{original_cols}->{$column} ||= $orig_columns->{column_values}->{$column}
      66        
340             if $orig_columns && $columns->{$column} ne $val;
341              
342 240         3812 $columns->{$column} = $val;
343             }
344 104         431 $self->call_trigger('post_inflate', $columns, $orig_columns);
345             }
346             }
347              
348             sub deflate {
349 1033 100   1033 0 6171 return unless $_[0]->{has_deflate};
350 248         546 my($self, $columns) = @_;
351 248         517 my $orig_columns;
352 248 50       1269 if (ref($columns) eq $self->{class}) {
    50          
353 0         0 $orig_columns = $columns;
354 0         0 $columns = $columns->{column_values};
355             } elsif (ref($columns) ne 'HASH') {
356 0         0 Carp::croak "required types 'HASH' or '$self->{class}' of inflate";
357             }
358 248         1206 $self->call_trigger('pre_deflate', $columns, $orig_columns);
359              
360 248         12405 for my $column (@{ $self->{deflate_columns} }) {
  248         946  
361 424 100       2230 next unless defined $columns->{$column};
362              
363 288         1035 my $opts = $self->{column}->{$column}->{options};
364 288         513 my $val = $columns->{$column};
365 288 100       6543 $val = $opts->{deflate}->($val) if ref($opts->{deflate}) eq 'CODE';
366              
367 288 100       4353 if ($self->{utf8_columns}->{$column}) {
368 136   50     739 my $charset = $opts->{charset} || 'utf8';
369 136         586 $val = Encode::encode($charset, $val);
370             }
371 288         14341 $columns->{$column} = $val;
372             }
373 248         937 $self->call_trigger('post_deflate', $columns, $orig_columns);
374             }
375              
376             sub set_default {
377 529     529 0 1074 my($self, $columns) = @_;
378              
379 529         1178 while (my($name, $conf) = each %{ $self->{column} }) {
  1847         7926  
380 1318 100       4728 next if exists $columns->{$name};
381 184 50       620 next unless exists $conf->{options};
382 184 100       877 next unless exists $conf->{options}->{default};
383              
384 14         28 my $default = $conf->{options}->{default};
385 14 100       40 if (ref($default) eq 'CODE') {
386 4         22 $columns->{$name} = $default->($self, $columns);
387             } else {
388 10         33 $columns->{$name} = $default;
389             }
390             }
391             }
392              
393             sub get_key_array_by_hash {
394 1594     1594 0 3654 my($self, $hash, $index) = @_;
395              
396 1594         2169 my $key;
397 1594 100 33     9287 $key = $self->{unique}->{$index} || $self->{index}->{$index} if $index;
398 1594   66     8462 $key ||= $self->{key};
399 1594 50       4686 $key = [ $key ] unless ref($key) eq 'ARRAY';
400              
401 1594         2363 my @keys;
402 1594         2259 for my $key (@{ $key }) {
  1594         4051  
403 1701 100       4943 last unless defined $hash->{$key};
404 1343         4954 push @keys, $hash->{$key};
405             }
406 1594         6941 \@keys;
407             }
408              
409             sub get_columns_hash_by_key_array_and_hash {
410 642     642 0 2197 my($self, $hash, $array, $index) = @_;
411 642         1283 my $ret = {};
412              
413             # by column
414 642         1179 for my $column (keys %{ $self->{column} }) {
  642         2924  
415 1338 100       6903 next unless exists $hash->{$column};
416 112         386 $ret->{$column} = $hash->{$column};
417             }
418              
419             # by key
420 642         1633 my $key;
421 642 100 33     1820 $key = $self->{unique}->{$index} || $self->{index}->{$index} || Carp::croak "Cannot find index '$index'" if $index;
422 642   66     3801 $key ||= $self->{key};
423 642 50       2849 $key = [ $key ] unless ref($key) eq 'ARRAY';
424              
425 642         1044 @{ $ret }{@{ $key }} = @{ $array };
  642         2464  
  642         1163  
  642         1291  
426 642         2460 $ret;
427             }
428              
429              
430             sub sql {
431 96     96 0 146 my $self = shift;
432 96   66     820 $self->{sql} ||= Data::Model::Schema::SQL->new($self);
433             }
434              
435              
436             1;