File Coverage

blib/lib/DBIx/Class/Smooth/Fields.pm
Criterion Covered Total %
statement 199 214 92.9
branch 22 34 64.7
condition 5 18 27.7
subroutine 43 44 97.7
pod 0 34 0.0
total 269 344 78.2


line stmt bran cond sub pod time code
1 3     3   105596 use 5.20.0;
  3         22  
2 3     3   14 use strict;
  3         6  
  3         56  
3 3     3   13 use warnings;
  3         7  
  3         182  
4              
5             package DBIx::Class::Smooth::Fields;
6              
7             # ABSTRACT: Short intro
8             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
9             our $VERSION = '0.0102';
10              
11 3     3   18 use Carp qw/croak/;
  3         5  
  3         162  
12 3     3   20 use List::Util qw/uniq/;
  3         5  
  3         196  
13 3     3   1426 use List::SomeUtils qw/any/;
  3         23512  
  3         208  
14 3     3   1077 use boolean;
  3         5505  
  3         17  
15 3         46 use Sub::Exporter::Progressive -setup => {
16             exports => [qw/
17             true
18             false
19             Relationship
20             ForeignKey
21             BitField
22             TinyIntField
23             SmallIntField
24             MediumIntField
25             IntegerField
26             BigIntField
27             SerialField
28             BooleanField
29             NumericField
30             NonNumericField
31             DecimalField
32             FloatField
33             DoubleField
34             VarcharField
35             CharField
36             VarbinaryField
37             BinaryField
38             TinyTextField
39             TextField
40             MediumTextField
41             LongTextField
42             TinyBlobField
43             BlobField
44             MediumBlobField
45             LongBlobField
46             EnumField
47             DateField
48             DateTimeField
49             TimestampField
50             TimeField
51             YearField
52             /],
53             groups => {
54             fields => [qw/
55             Relationship
56             ForeignKey
57             BitField
58             TinyIntField
59             SmallIntField
60             MediumIntField
61             IntegerField
62             BigIntField
63             SerialField
64             BooleanField
65             NumericField
66             NonNumericField
67             DecimalField
68             FloatField
69             DoubleField
70             VarcharField
71             CharField
72             VarbinaryField
73             BinaryField
74             TinyTextField
75             TextField
76             MediumTextField
77             LongTextField
78             TinyBlobField
79             BlobField
80             MediumBlobField
81             LongBlobField
82             EnumField
83             DateField
84             DateTimeField
85             TimestampField
86             TimeField
87             YearField
88             /],
89             },
90 3     3   803 };
  3         1101  
91              
92 3     3   1393 use experimental qw/postderef signatures/;
  3         3388  
  3         26  
93              
94 70     70 0 104 sub merge($first, $second) {
  70         96  
  70         80  
  70         98  
95 70         126 my $merged = do_merge($first, $second);
96              
97 70 100       158 if(!exists $merged->{'extra'}) {
98 67         107 $merged->{'extra'} = {};
99             }
100 70         109 $merged->{'_smooth'} = {};
101              
102 70         185 for my $key (keys $merged->%*) {
103 339 100       930 if($key =~ m{^-(.*)}) {
    50          
    50          
    50          
    50          
104 12         25 my $clean_key = $1;
105 12         32 $merged->{'extra'}{ $clean_key } = delete $merged->{ $key };
106             }
107             elsif($key eq 'many') {
108 0   0     0 $merged->{'_smooth'}{'has_many'} = delete $merged->{'many'} || [];
109             }
110             elsif($key eq 'might') {
111 0   0     0 $merged->{'_smooth'}{'might_have'} = delete $merged->{'might'} || [];
112             }
113             elsif($key eq 'one') {
114 0   0     0 $merged->{'_smooth'}{'has_one'} = delete $merged->{'one'} || [];
115             }
116             elsif($key eq 'across') {
117 0         0 my $acrosses = delete $merged->{'across'};
118 0         0 for (my $i = 0; $i < scalar $acrosses->@*; ++$i) {
119 0         0 my $from = $acrosses->[$i];
120 0         0 my $to = $acrosses->[$i + 1];
121 0         0 $merged->{'_smooth'}{'across'}{ $from }{ $to } = 1;
122             }
123             }
124             }
125              
126 70         260 my %alias = (
127             nullable => 'is_nullable',
128             auto_increment => 'is_auto_increment',
129             foreign_key => 'is_foreign_key',
130             default => 'default_value',
131             );
132              
133 70         143 for my $alias (keys %alias) {
134 280 100       539 if(exists $merged->{ $alias }) {
135 13         21 my $actual = $alias{ $alias };
136 13         34 $merged->{ $actual } = delete $merged->{ $alias };
137             }
138             }
139              
140 70 100       129 if(exists $merged->{'default_sql'}) {
141 4 100       11 if(!defined $merged->{'default_sql'}) {
142 1         2 delete $merged->{'default_sql'};
143 1         2 $merged->{'default_value'} = \'NULL';
144             }
145             else {
146 3         5 my $default_sql = delete $merged->{'default_sql'};
147 3         5 $merged->{'default_value'} = \$default_sql;
148             }
149             }
150              
151 70 50       181 if(!scalar keys $merged->{'_smooth'}->%*) {
152 70         131 delete $merged->{'_smooth'};
153             }
154 70 100       135 if(!scalar keys $merged->{'extra'}->%*) {
155 60         185 delete $merged->{'extra'};
156             }
157 70         541 return $merged;
158             }
159              
160 70     70 0 85 sub do_merge($first, $second) {
  70         95  
  70         84  
  70         82  
161 70         90 my $merged = {};
162 70         106 for my $key (uniq (keys %{ $first }, keys %{ $second })) {
  70         158  
  70         266  
163 202 100 66     670 if(exists $first->{ $key } && !exists $second->{ $key }) {
    50 33        
164 73         136 $merged->{ $key } = $first->{ $key };
165             }
166             elsif(!exists $first->{ $key } && exists $second->{ $key }) {
167 129         210 $merged->{ $key } = $second->{ $key };
168             }
169             else {
170 0 0 0     0 if(ref $first->{ $key } ne 'HASH' && $second->{ $key } ne 'HASH') {
171 0         0 $merged->{ $key } = $first->{ $key };
172             }
173             else {
174 0         0 $merged->{ $key } = do_merge($first->{ $key }, $second->{ $key });
175             }
176             }
177             }
178              
179 70         180 return $merged;
180             }
181              
182             # this can only be used in the best case, where we can lift the definition from the primary key it points to
183             # and also does belongs_to<->has_many relationships
184 2     2 0 4 sub ForeignKey(%settings) {
  2         4  
  2         2  
185             # 'sql' is the attr to the relationship
186             # 'related_name' is the name of the inverse relationship, set to undef to skip creation
187             # 'related_sql' is the attr to the inverse relationship
188 2         8 my @approved_keys = qw/nullable indexed sql related_name related_sql/;
189 2         4 my @keys_in_settings = keys %settings;
190              
191             KEY:
192 2         4 for my $key (@keys_in_settings) {
193 0 0   0   0 next KEY if any { $key eq $_ } @approved_keys;
  0         0  
194 0         0 delete $settings{ $key };
195             }
196              
197 2         8 return merge { _smooth_foreign_key => 1 }, \%settings;
198             }
199              
200             # base fields
201 29     29 0 690 sub NumericField(%settings) {
  29         79  
  29         47  
202 29         97 return merge { is_numeric => 1 }, \%settings;
203             }
204 36     36 0 1820 sub NonNumericField(%settings) {
  36         78  
  36         44  
205 36         93 return merge { is_numeric => 0 }, \%settings;
206             }
207              
208             # data types - integers
209 1     1 0 1617 sub BitField(%settings) {
  1         3  
  1         2  
210 1         5 return NumericField(data_type => 'bit', %settings);
211             }
212 1     1 0 674 sub TinyIntField(%settings) {
  1         3  
  1         2  
213 1         4 return NumericField(data_type => 'tinyint', %settings);
214             }
215 1     1 0 689 sub SmallIntField(%settings) {
  1         2  
  1         3  
216 1         5 return NumericField(data_type => 'smallint', %settings);
217             }
218 1     1 0 668 sub MediumIntField(%settings) {
  1         4  
  1         2  
219 1         5 return NumericField(data_type => 'mediumint', %settings);
220             }
221 11     11 0 24382 sub IntegerField(%settings) {
  11         33  
  11         16  
222 11         38 return NumericField(data_type => 'integer', %settings);
223             }
224 1     1 0 589 sub BigIntField(%settings) {
  1         4  
  1         2  
225 1         6 return NumericField(data_type => 'bigint', %settings);
226             }
227 2     2 0 1194 sub SerialField(%settings) {
  2         6  
  2         3  
228 2         8 return NumericField(data_type => 'serial', %settings);
229             }
230 1     1 0 584 sub BooleanField(%settings) {
  1         3  
  1         2  
231 1         5 return NumericField(data_type => 'boolean', %settings);
232             }
233              
234             # data types - other numericals
235 6     6 0 6804 sub DecimalField(%settings) {
  6         16  
  6         10  
236 6         57 return NumericField(data_type => 'decimal', %settings);
237             }
238 2     2 0 1168 sub FloatField(%settings) {
  2         5  
  2         2  
239 2         7 return NumericField(data_type => 'float', %settings);
240             }
241 1     1 0 492 sub DoubleField(%settings) {
  1         2  
  1         2  
242 1         5 return NumericField(data_type => 'double', %settings);
243             }
244              
245             # data types - strings
246 11     11 0 2032 sub VarcharField(%settings) {
  11         27  
  11         15  
247 11         33 return NonNumericField(data_type => 'varchar', %settings);
248             }
249 1     1 0 500 sub CharField(%settings) {
  1         2  
  1         2  
250 1         5 return NonNumericField(data_type => 'char', %settings);
251             }
252 1     1 0 484 sub VarbinaryField(%settings) {
  1         2  
  1         2  
253 1         4 return NonNumericField(data_type => 'varbinary', %settings);
254             }
255 1     1 0 481 sub BinaryField(%settings) {
  1         3  
  1         2  
256 1         3 return NonNumericField(data_type => 'binary', %settings);
257             }
258              
259 1     1 0 480 sub TinyTextField(%settings) {
  1         2  
  1         2  
260 1         4 return NonNumericField(data_type => 'tinytext', %settings);
261             }
262 1     1 0 477 sub TextField(%settings) {
  1         3  
  1         2  
263 1         4 return NonNumericField(data_type => 'text', %settings);
264             }
265 1     1 0 516 sub MediumTextField(%settings) {
  1         2  
  1         3  
266 1         3 return NonNumericField(data_type => 'mediumtext', %settings);
267             }
268 1     1 0 479 sub LongTextField(%settings) {
  1         2  
  1         2  
269 1         5 return NonNumericField(data_type => 'longtext', %settings);
270             }
271 1     1 0 500 sub TinyBlobField(%settings) {
  1         3  
  1         2  
272 1         5 return NonNumericField(data_type => 'tinyblob', %settings);
273             }
274 1     1 0 476 sub BlobField(%settings) {
  1         2  
  1         2  
275 1         4 return NonNumericField(data_type => 'blob', %settings);
276             }
277 1     1 0 482 sub MediumBlobField(%settings) {
  1         2  
  1         2  
278 1         4 return NonNumericField(data_type => 'mediumblob', %settings);
279             }
280 1     1 0 474 sub LongBlobField(%settings) {
  1         3  
  1         1  
281 1         19 return NonNumericField(data_type => 'longblob', %settings);
282             }
283              
284 3     3 0 2121 sub EnumField(%settings) {
  3         9  
  3         4  
285 3 50 66     14 if(exists $settings{'extra'} && exists $settings{'extra'}{'list'}) {
    50          
286             # all good
287             }
288             elsif(exists $settings{'-list'}) {
289 3         7 $settings{'extra'}{'list'} = delete $settings{'list'};
290             }
291             else {
292 0         0 croak qq{'enum' expects '-list => [qw/the possible values/]' or 'extra => { list => [qw/the possible values/] }'};
293             }
294 3         11 return merge { data_type => 'enum', is_numeric => 0 }, \%settings;
295             }
296              
297             # data types - dates and times
298 3     3 0 1864 sub DateField(%settings) {
  3         7  
  3         5  
299 3         13 return NonNumericField(data_type => 'date', %settings);
300             }
301 3     3 0 1969 sub DateTimeField(%settings) {
  3         6  
  3         4  
302 3         9 return NonNumericField(data_type => 'datetime', %settings);
303             }
304 1     1 0 501 sub TimestampField(%settings) {
  1         3  
  1         2  
305 1         4 return NonNumericField(data_type => 'timestamp', %settings);
306             }
307 1     1 0 638 sub TimeField(%settings) {
  1         3  
  1         2  
308 1         8 return NonNumericField(data_type => 'time', %settings);
309             }
310 3     3 0 519 sub YearField(%settings) {
  3         6  
  3         5  
311 3         10 return NonNumericField(data_type => 'year', %settings);
312             }
313              
314             1;
315              
316             __END__
317              
318             =pod
319              
320             =encoding UTF-8
321              
322             =head1 NAME
323              
324             DBIx::Class::Smooth::Fields - Short intro
325              
326             =head1 VERSION
327              
328             Version 0.0102, released 2019-12-22.
329              
330             =head1 SYNOPSIS
331              
332             use DBIx::Class::Smooth;
333              
334             =head1 DESCRIPTION
335              
336             DBIx::Class::Smooth is ...
337              
338             =head1 SEE ALSO
339              
340             =head1 SOURCE
341              
342             L<https://github.com/Csson/p5-DBIx-Class-Smooth>
343              
344             =head1 HOMEPAGE
345              
346             L<https://metacpan.org/release/DBIx-Class-Smooth>
347              
348             =head1 AUTHOR
349              
350             Erik Carlsson <info@code301.com>
351              
352             =head1 COPYRIGHT AND LICENSE
353              
354             This software is copyright (c) 2018 by Erik Carlsson.
355              
356             This is free software; you can redistribute it and/or modify it under
357             the same terms as the Perl 5 programming language system itself.
358              
359             =cut