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   107982 use 5.20.0;
  3         22  
2 3     3   19 use strict;
  3         7  
  3         66  
3 3     3   17 use warnings;
  3         6  
  3         199  
4              
5             package DBIx::Class::Smooth::Fields;
6              
7             # ABSTRACT: Short intro
8             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
9             our $VERSION = '0.0101';
10              
11 3     3   22 use Carp qw/croak/;
  3         6  
  3         264  
12 3     3   20 use List::Util qw/uniq/;
  3         5  
  3         219  
13 3     3   1626 use List::SomeUtils qw/any/;
  3         26330  
  3         253  
14 3     3   1277 use boolean;
  3         5601  
  3         30  
15 3         56 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   849 };
  3         1426  
91              
92 3     3   1547 use experimental qw/postderef signatures/;
  3         3480  
  3         30  
93              
94 70     70 0 118 sub merge($first, $second) {
  70         103  
  70         98  
  70         95  
95 70         164 my $merged = do_merge($first, $second);
96              
97 70 100       172 if(!exists $merged->{'extra'}) {
98 67         128 $merged->{'extra'} = {};
99             }
100 70         133 $merged->{'_smooth'} = {};
101              
102 70         222 for my $key (keys $merged->%*) {
103 339 100       1092 if($key =~ m{^-(.*)}) {
    50          
    50          
    50          
    50          
104 12         28 my $clean_key = $1;
105 12         37 $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         297 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         175 for my $alias (keys %alias) {
134 280 100       553 if(exists $merged->{ $alias }) {
135 13         23 my $actual = $alias{ $alias };
136 13         39 $merged->{ $actual } = delete $merged->{ $alias };
137             }
138             }
139              
140 70 100       160 if(exists $merged->{'default_sql'}) {
141 4 100       10 if(!defined $merged->{'default_sql'}) {
142 1         3 delete $merged->{'default_sql'};
143 1         2 $merged->{'default_value'} = \'NULL';
144             }
145             else {
146 3         7 my $default_sql = delete $merged->{'default_sql'};
147 3         7 $merged->{'default_value'} = \$default_sql;
148             }
149             }
150              
151 70 50       225 if(!scalar keys $merged->{'_smooth'}->%*) {
152 70         161 delete $merged->{'_smooth'};
153             }
154 70 100       210 if(!scalar keys $merged->{'extra'}->%*) {
155 60         117 delete $merged->{'extra'};
156             }
157 70         624 return $merged;
158             }
159              
160 70     70 0 105 sub do_merge($first, $second) {
  70         96  
  70         137  
  70         89  
161 70         120 my $merged = {};
162 70         121 for my $key (uniq (keys %{ $first }, keys %{ $second })) {
  70         189  
  70         310  
163 202 100 66     777 if(exists $first->{ $key } && !exists $second->{ $key }) {
    50 33        
164 73         169 $merged->{ $key } = $first->{ $key };
165             }
166             elsif(!exists $first->{ $key } && exists $second->{ $key }) {
167 129         260 $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         204 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         5  
  2         4  
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         6 my @approved_keys = qw/nullable indexed sql related_name related_sql/;
189 2         5 my @keys_in_settings = keys %settings;
190              
191             KEY:
192 2         6 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         6 return merge { _smooth_foreign_key => 1 }, \%settings;
198             }
199              
200             # base fields
201 29     29 0 849 sub NumericField(%settings) {
  29         92  
  29         53  
202 29         102 return merge { is_numeric => 1 }, \%settings;
203             }
204 36     36 0 2375 sub NonNumericField(%settings) {
  36         97  
  36         57  
205 36         113 return merge { is_numeric => 0 }, \%settings;
206             }
207              
208             # data types - integers
209 1     1 0 1164 sub BitField(%settings) {
  1         3  
  1         2  
210 1         5 return NumericField(data_type => 'bit', %settings);
211             }
212 1     1 0 623 sub TinyIntField(%settings) {
  1         3  
  1         1  
213 1         5 return NumericField(data_type => 'tinyint', %settings);
214             }
215 1     1 0 602 sub SmallIntField(%settings) {
  1         3  
  1         1  
216 1         7 return NumericField(data_type => 'smallint', %settings);
217             }
218 1     1 0 706 sub MediumIntField(%settings) {
  1         4  
  1         3  
219 1         4 return NumericField(data_type => 'mediumint', %settings);
220             }
221 11     11 0 29899 sub IntegerField(%settings) {
  11         34  
  11         19  
222 11         40 return NumericField(data_type => 'integer', %settings);
223             }
224 1     1 0 614 sub BigIntField(%settings) {
  1         4  
  1         2  
225 1         6 return NumericField(data_type => 'bigint', %settings);
226             }
227 2     2 0 1239 sub SerialField(%settings) {
  2         4  
  2         3  
228 2         8 return NumericField(data_type => 'serial', %settings);
229             }
230 1     1 0 607 sub BooleanField(%settings) {
  1         2  
  1         3  
231 1         5 return NumericField(data_type => 'boolean', %settings);
232             }
233              
234             # data types - other numericals
235 6     6 0 4774 sub DecimalField(%settings) {
  6         13  
  6         11  
236 6         22 return NumericField(data_type => 'decimal', %settings);
237             }
238 2     2 0 1460 sub FloatField(%settings) {
  2         6  
  2         3  
239 2         7 return NumericField(data_type => 'float', %settings);
240             }
241 1     1 0 614 sub DoubleField(%settings) {
  1         2  
  1         3  
242 1         5 return NumericField(data_type => 'double', %settings);
243             }
244              
245             # data types - strings
246 11     11 0 2145 sub VarcharField(%settings) {
  11         31  
  11         19  
247 11         82 return NonNumericField(data_type => 'varchar', %settings);
248             }
249 1     1 0 605 sub CharField(%settings) {
  1         3  
  1         3  
250 1         4 return NonNumericField(data_type => 'char', %settings);
251             }
252 1     1 0 605 sub VarbinaryField(%settings) {
  1         3  
  1         2  
253 1         5 return NonNumericField(data_type => 'varbinary', %settings);
254             }
255 1     1 0 647 sub BinaryField(%settings) {
  1         3  
  1         2  
256 1         5 return NonNumericField(data_type => 'binary', %settings);
257             }
258              
259 1     1 0 631 sub TinyTextField(%settings) {
  1         3  
  1         3  
260 1         5 return NonNumericField(data_type => 'tinytext', %settings);
261             }
262 1     1 0 613 sub TextField(%settings) {
  1         2  
  1         2  
263 1         6 return NonNumericField(data_type => 'text', %settings);
264             }
265 1     1 0 602 sub MediumTextField(%settings) {
  1         3  
  1         2  
266 1         5 return NonNumericField(data_type => 'mediumtext', %settings);
267             }
268 1     1 0 604 sub LongTextField(%settings) {
  1         2  
  1         3  
269 1         5 return NonNumericField(data_type => 'longtext', %settings);
270             }
271 1     1 0 635 sub TinyBlobField(%settings) {
  1         3  
  1         2  
272 1         6 return NonNumericField(data_type => 'tinyblob', %settings);
273             }
274 1     1 0 620 sub BlobField(%settings) {
  1         2  
  1         2  
275 1         4 return NonNumericField(data_type => 'blob', %settings);
276             }
277 1     1 0 610 sub MediumBlobField(%settings) {
  1         3  
  1         3  
278 1         6 return NonNumericField(data_type => 'mediumblob', %settings);
279             }
280 1     1 0 605 sub LongBlobField(%settings) {
  1         3  
  1         2  
281 1         19 return NonNumericField(data_type => 'longblob', %settings);
282             }
283              
284 3     3 0 2679 sub EnumField(%settings) {
  3         10  
  3         6  
285 3 50 66     18 if(exists $settings{'extra'} && exists $settings{'extra'}{'list'}) {
    50          
286             # all good
287             }
288             elsif(exists $settings{'-list'}) {
289 3         10 $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         14 return merge { data_type => 'enum', is_numeric => 0 }, \%settings;
295             }
296              
297             # data types - dates and times
298 3     3 0 789 sub DateField(%settings) {
  3         7  
  3         6  
299 3         15 return NonNumericField(data_type => 'date', %settings);
300             }
301 3     3 0 2049 sub DateTimeField(%settings) {
  3         7  
  3         6  
302 3         10 return NonNumericField(data_type => 'datetime', %settings);
303             }
304 1     1 0 658 sub TimestampField(%settings) {
  1         5  
  1         2  
305 1         7 return NonNumericField(data_type => 'timestamp', %settings);
306             }
307 1     1 0 827 sub TimeField(%settings) {
  1         4  
  1         2  
308 1         10 return NonNumericField(data_type => 'time', %settings);
309             }
310 3     3 0 619 sub YearField(%settings) {
  3         6  
  3         6  
311 3         11 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.0101, released 2018-11-29.
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