File Coverage

blib/lib/WWW/Shopify/Field.pm
Criterion Covered Total %
statement 102 255 40.0
branch 0 66 0.0
condition 0 15 0.0
subroutine 34 127 26.7
pod 0 20 0.0
total 136 483 28.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3 1     1   3 use strict;
  1         5  
  1         20  
4 1     1   3 use warnings;
  1         1  
  1         17  
5              
6 1     1   297 use WWW::Shopify::Field::Text;
  1         1  
  1         20  
7 1     1   315 use WWW::Shopify::Field::Relation;
  1         1  
  1         19  
8 1     1   487 use WWW::Shopify::Field::String;
  1         2  
  1         20  
9 1     1   321 use WWW::Shopify::Field::Identifier;
  1         2  
  1         22  
10              
11             package main;
12 1     1   3 use String::Random qw(random_regex random_string);
  1         1  
  1         37  
13 1     1   3 use Data::Random qw(rand_datetime rand_words);
  1         1  
  1         412  
14              
15             =head2 WWW::Shopify::Model::Field
16              
17             The main object representing a field on a Shopify object. Contains mainly a name, and a type. Can also contain more data when the need arises to represent something more specifically.
18              
19             There are a lot of these, so I'm not going to list them; most of the distinctions are made so that databases with reasonable data can be generated.
20              
21             =cut
22              
23              
24             package WWW::Shopify::Field;
25             sub new($) {
26 0     0 0   my $package = shift;
27 0           my $calling_package = caller(0);
28 0           return bless {
29             arguments => [@_],
30             name => undef,
31             owner => $calling_package
32             }, $package;
33             }
34 0 0   0 0   sub name { $_[0]->{name} = $_[1] if defined $_[1]; return $_[0]->{name}; }
  0            
35 0     0 0   sub sql_type($) { die ref($_[0]); }
36 0     0 0   sub is_relation { return undef; }
37 0     0 0   sub is_qualifier { return undef; }
38 0     0 0   sub qualifier { return undef; }
39 0     0 0   sub to_shopify($$) { return $_[1]; }
40 0     0 0   sub from_shopify($$) { return $_[1]; }
41 0     0 0   sub generate($) { die "Can't generate $_[0]"; }
42 0     0 0   sub validate($) { die "Can't validate $_[0]"; }
43 0 0   0 0   sub owner { $_[0]->{owner} = $_[1] if defined $_[1]; return $_[0]->{owner}; }
  0            
44              
45 0     0 0   sub is_db_belongs_to { return undef; }
46 0     0 0   sub is_db_has_many { return undef; }
47 0     0 0   sub is_db_many_many { return undef; }
48 0     0 0   sub is_db_has_one { return undef; }
49              
50             use constant {
51 1         73 TYPE_QUANTITATIVE => 0,
52             TYPE_QUALITATIVE => 1,
53             TYPE_BOOLEAN => 2
54 1     1   5 };
  1         0  
55              
56             use constant {
57             # No order, no set distance (E.G. Telephone Numbers)
58 1         62 SET_NOMINAL => 0,
59             # No set distance between values.
60             SET_ORDINAL => 1,
61             # Distinguishable distance between values. (E.G. Real Numbers)
62             SET_CARDINAL => 2
63 1     1   3 };
  1         21  
64              
65 1     1   4 use base 'Exporter';
  1         1  
  1         327  
66             our @EXPORT_OK = qw(TYPE_QUANTITATIVE TYPE_QUALITATIVE TYPE_BOOLEAN SET_NOMINAL SET_ORDINAL SET_CARDINAL);
67              
68 0     0 0   sub data_type { return TYPE_QUALITATIVE; }
69 0     0 0   sub is_qualitative { return $_[0]->data_type == TYPE_QUANTITATIVE; }
70 0     0 0   sub is_quantitative { return $_[0]->data_type == TYPE_QUALITATIVE; }
71 0     0 0   sub is_boolean { return $_[0]->data_type == TYPE_BOOLEAN; }
72 0 0   0 0   sub number_type { return $_[0]->is_quantitative ? SET_CARDINAL : SET_NOMINAL }
73              
74             package WWW::Shopify::Field::Hook;
75 1     1   5 use parent 'WWW::Shopify::Field';
  1         0  
  1         3  
76 0     0     sub new($) { return bless { internal => $_[1], qualifier => $_[2] }, $_[0]; }
77 0     0     sub sql_type($) { return shift->{internal}->sql_type(@_); }
78 0     0     sub is_relation { return shift->{internal}->is_relation(@_); }
79 0     0     sub to_shopify($$) { return shift->{internal}->to_shopify(@_); }
80 0     0     sub from_shopify($$) { return shift->{internal}->from_shopify(@_); }
81 0     0     sub generate($) { return shift->{internal}->generate(@_); }
82 0     0     sub relation($) { return shift->{internal}->relation(@_); }
83 0     0     sub is_many { return shift->{internal}->is_many(@_); }
84 0     0     sub is_one { return shift->{internal}->is_one(@_); }
85 0     0     sub is_own { return shift->{internal}->is_own(@_); }
86 0     0     sub is_reference { return shift->{internal}->is_reference(@_); }
87              
88             package WWW::Shopify::Field::Int;
89 1     1   251 use parent 'WWW::Shopify::Field';
  1         1  
  1         5  
90 1     1   424 use String::Numeric qw(is_int);
  1         1861  
  1         147  
91 0     0     sub sql_type { return "int"; }
92             sub generate($) {
93 0 0   0     return int(rand(10000)) if (int(@{$_[0]->{arguments}}) == 0);
  0            
94 0 0         return $_[0]->{arguments}->[0] if (int(@{$_[0]->{arguments}}) == 1);
  0            
95 0           return int(rand($_[0]->{arguments}->[1] - $_[0]->{arguments}->[0] + 1) + $_[0]->{arguments}->[0]);
96             }
97 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
98 0     0     sub validate($$) { return is_int($_[1]); }
99              
100             package WWW::Shopify::Field::BigInt;
101 1     1   4 use parent 'WWW::Shopify::Field';
  1         10  
  1         8  
102 1     1   47 use String::Numeric qw(is_int);
  1         1  
  1         137  
103 0     0     sub sql_type { return "bigint"; }
104             sub generate($) {
105 0 0   0     return int(rand(10000000)) if (int(@{$_[0]->{arguments}}) == 0);
  0            
106 0 0         return $_[0]->{arguments}->[0] if (int(@{$_[0]->{arguments}}) == 1);
  0            
107 0           return int(rand($_[0]->{arguments}->[1] - $_[0]->{arguments}->[0] + 1) + $_[0]->{arguments}->[0]);
108             }
109 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
110 0     0     sub validate { return is_int($_[1]); }
111              
112             package WWW::Shopify::Field::Boolean;
113 1     1   4 use Scalar::Util qw(looks_like_number);
  1         1  
  1         40  
114 1     1   566 use JSON;
  1         7675  
  1         3  
115 1     1   98 use parent 'WWW::Shopify::Field';
  1         1  
  1         4  
116 0     0     sub sql_type { return "bool"; }
117 0     0     sub generate { return (rand() < 0.5); }
118 0 0 0 0     sub validate { return looks_like_number($_[1]) ? ($_[1] == 0 || $_[1] == 1) : (lc($_[1]) == 'true' || lc($_[1]) == 'false'); }
      0        
119 0     0     sub data_type { return WWW::Shopify::Field::TYPE_BOOLEAN; }
120 0 0   0     sub to_shopify { return $_[1] ? JSON::true : JSON::false; }
121 0 0   0     sub from_shopify { return $_[1] ? 1 : 0; }
122              
123             package WWW::Shopify::Field::Float;
124 1     1   143 use parent 'WWW::Shopify::Field';
  1         1  
  1         2  
125 1     1   38 use String::Numeric qw(is_float);
  1         1  
  1         136  
126 0     0     sub sql_type { return "float"; }
127             sub generate($) {
128 0 0   0     return rand() * 10000.0 if (int(@{$_[0]->{arguments}}) == 0);
  0            
129 0 0         return $_[0]->{arguments}->[0] if (int(@{$_[0]->{arguments}}) == 1);
  0            
130 0           return rand($_[0]->{arguments}->[1] - $_[0]->{arguments}->[0] + 1) + $_[0]->{arguments}->[0];
131             }
132 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
133 0     0     sub validate($$) { return is_float($_[1]); }
134              
135             package WWW::Shopify::Field::Timestamp;
136 1     1   3 use parent 'WWW::Shopify::Field';
  1         1  
  1         3  
137 1     1   37 use String::Numeric qw(is_int);
  1         1  
  1         129  
138 0     0     sub sql_type { return "bigint"; }
139             sub generate($) {
140 0 0   0     return int(rand(10000000)) if (int(@{$_[0]->{arguments}}) == 0);
  0            
141 0 0         return $_[0]->{arguments}->[0] if (int(@{$_[0]->{arguments}}) == 1);
  0            
142 0           return int(rand($_[0]->{arguments}->[1] - $_[0]->{arguments}->[0] + 1) + $_[0]->{arguments}->[0]);
143             }
144 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
145 0     0     sub validate { return is_int($_[1]); }
146              
147             package WWW::Shopify::Field::Timezone;
148 1     1   4 use parent 'WWW::Shopify::Field';
  1         0  
  1         3  
149 0     0     sub sql_type { return "varchar(255)"; }
150              
151             my %from_shopify_timezones = (
152             "(GMT-05:00) Eastern Time (US & Canada)" => "America/New_York",
153             "(GMT-11:00) International Date Line West" => "-1100",
154             "(GMT-11:00) Midway Island" => "Pacific/Midway",
155             "(GMT-11:00) American Samoa" => "Pacific/Pago_Pago",
156             "(GMT-10:00) Hawaii" => "Pacific/Honolulu",
157             "(GMT-09:00) Alaska" => "America/Anchorage",
158             "(GMT-08:00) Pacific Time (US & Canada)" => "PST8PDT",
159             "(GMT-08:00) Tijuana" => "America/Tijuana",
160             "(GMT-07:00) Mountain Time (US & Canada)" => "MST7MDT",
161             "(GMT-07:00) Arizona" => "MST",
162             "(GMT-07:00) Chihuahua" => "America/Chihuahua",
163             "(GMT-07:00) Mazatlan" => "MST",
164             "(GMT-06:00) Central Time (US & Canada)" => "CST6CDT",
165             "(GMT-06:00) Saskatchewan" => "-0600",
166             "(GMT-06:00) Guadalajara" => "CST6CDT",
167             "(GMT-06:00) Mexico City" => "CST6CDT",
168             "(GMT-06:00) Monterrey" => "America/Monterrey",
169             "(GMT-06:00) Central America" => "CST6CDT",
170             "(GMT-05:00) Indiana (East)" => "EST5EDT",
171             "(GMT-05:00) Bogota" => "America/Bogota",
172             "(GMT-05:00) Lima" => "America/Lima",
173             "(GMT-05:00) Quito" => "-0500",
174             "(GMT-04:00) Atlantic Time (Canada)" => "America/Halifax",
175             "(GMT-04:30) Caracas" => "America/Caracas",
176             "(GMT-04:00) La Paz" => "-04:00",
177             "(GMT-04:00) Santiago" => "America/Santiago",
178             "(GMT-03:30) Newfoundland" => "America/La_Paz",
179             "(GMT-03:00) Brasilia" => "America/Sao_Paulo",
180             "(GMT-03:00) Buenos Aires" => "America/Argentina/Buenos_Aires",
181             "(GMT-04:00) Georgetown" => "America/Guyana",
182             "(GMT-03:00) Greenland" => "-0300",
183             "(GMT-02:00) Mid-Atlantic" => "-0200",
184             "(GMT-01:00) Azores" => "Atlantic/Azores",
185             "(GMT-01:00) Cape Verde Is." => "Atlantic/Cape_Verde",
186             "(GMT+00:00) Dublin" => "Europe/Dublin",
187             "(GMT+00:00) Edinburgh" => "Europe/London",
188             "(GMT+00:00) Lisbon" => "Europe/Lisbon",
189             "(GMT+00:00) London" => "Europe/London",
190             "(GMT+00:00) Casablanca" => "Africa/Casablanca",
191             "(GMT+00:00) Monrovia" => "Africa/Monrovia",
192             "(GMT+00:00) UTC" => "UTC",
193             "(GMT+01:00) Belgrade" => "Europe/Belgrade",
194             "(GMT+01:00) Bratislava" => "Europe/Bratislava",
195             "(GMT+01:00) Budapest" => "Europe/Budapest",
196             "(GMT+01:00) Ljubljana" => "Europe/Ljubljana",
197             "(GMT+01:00) Prague" => "Europe/Prague",
198             "(GMT+01:00) Sarajevo" => "Europe/Sarajevo",
199             "(GMT+01:00) Skopje" => "Europe/Skopje",
200             "(GMT+01:00) Warsaw" => "Europe/Warsaw",
201             "(GMT+01:00) Zagreb" => "Europe/Zagreb",
202             "(GMT+01:00) Brussels" => "Europe/Brussels",
203             "(GMT+01:00) Copenhagen" => "Europe/Copenhagen",
204             "(GMT+01:00) Madrid" => "Europe/Madrid",
205             "(GMT+01:00) Paris" => "Europe/Paris",
206             "(GMT+01:00) Amsterdam" => "Europe/Amsterdam",
207             "(GMT+01:00) Berlin" => "Europe/Berlin",
208             "(GMT+01:00) Bern" => "Europe/Zurich",
209             "(GMT+01:00) Rome" => "Europe/Rome",
210             "(GMT+01:00) Stockholm" => "Europe/Stockholm",
211             "(GMT+01:00) Vienna" => "Europe/Vienna",
212             "(GMT+01:00) West Central Africa" => "+0100",
213             "(GMT+02:00) Bucharest" => "Europe/Bucharest",
214             "(GMT+02:00) Cairo" => "Africa/Cairo",
215             "(GMT+02:00) Helsinki" => "Europe/Helsinki",
216             "(GMT+02:00) Kyiv" => "Europe/Kiev",
217             "(GMT+02:00) Riga" => "Europe/Riga",
218             "(GMT+02:00) Sofia" => "Europe/Sofia",
219             "(GMT+02:00) Tallinn" => "Europe/Tallinn",
220             "(GMT+02:00) Vilnius" => "Europe/Vilnius",
221             "(GMT+02:00) Athens" => "Europe/Athens",
222             "(GMT+02:00) Istanbul" => "Europe/Istanbul",
223             "(GMT+03:00) Minsk" => "Europe/Minsk",
224             "(GMT+02:00) Jerusalem" => "Asia/Jerusalem",
225             "(GMT+02:00) Harare" => "Africa/Harare",
226             "(GMT+02:00) Pretoria" => "Africa/Maseru",
227             "(GMT+04:00) Moscow" => "Europe/Moscow",
228             "(GMT+04:00) St. Petersburg" => "Europe/Moscow",
229             "(GMT+04:00) Volgograd" => "Europe/Volgograd",
230             "(GMT+03:00) Kuwait" => "Asia/Kuwait",
231             "(GMT+03:00) Riyadh" => "Asia/Riyadh",
232             "(GMT+03:00) Nairobi" => "Africa/Nairobi",
233             "(GMT+03:00) Baghdad" => "Asia/Baghdad",
234             "(GMT+03:30) Tehran" => "Asia/Tehran",
235             "(GMT+04:00) Abu Dhabi" => "+0400",
236             "(GMT+04:00) Muscat" => "Asia/Muscat",
237             "(GMT+04:00) Baku" => "Asia/Baku",
238             "(GMT+04:00) Tbilisi" => "Asia/Tbilisi",
239             "(GMT+04:00) Yerevan" => "Asia/Yerevan",
240             "(GMT+04:30) Kabul" => "Asia/Kabul",
241             "(GMT+06:00) Ekaterinburg" => "Asia/Yekaterinburg",
242             "(GMT+05:00) Islamabad" => "+05:00",
243             "(GMT+05:00) Karachi" => "Asia/Karachi",
244             "(GMT+05:00) Tashkent" => "Asia/Tashkent",
245             "(GMT+05:30) Chennai" => "+05:30",
246             "(GMT+05:30) Kolkata" => "Asia/Kolkata",
247             "(GMT+05:30) Mumbai" => "+05:30",
248             "(GMT+05:30) New Delhi" => "+05:30",
249             "(GMT+05:45) Kathmandu" => "Asia/Kathmandu",
250             "(GMT+06:00) Astana" => "Asia/Thimphu",
251             "(GMT+06:00) Dhaka" => "Asia/Dhaka",
252             "(GMT+05:30) Sri Jayawardenepura" => "+0530",
253             "(GMT+06:00) Almaty" => "Asia/Almaty",
254             "(GMT+07:00) Novosibirsk" => "Asia/Novosibirsk",
255             "(GMT+06:30) Rangoon" => "Asia/Rangoon",
256             "(GMT+07:00) Bangkok" => "Asia/Bangkok",
257             "(GMT+07:00) Hanoi" => "+0700",
258             "(GMT+07:00) Jakarta" => "Asia/Jakarta",
259             "(GMT+08:00) Krasnoyarsk" => "Asia/Krasnoyarsk",
260             "(GMT+08:00) Beijing" => "Asia/Shanghai",
261             "(GMT+08:00) Chongqing" => "Asia/Chongqing",
262             "(GMT+08:00) Hong Kong" => "Asia/Hong_Kong",
263             "(GMT+08:00) Urumqi" => "Asia/Urumqi",
264             "(GMT+08:00) Kuala Lumpur" => "Asia/Kuala_Lumpur",
265             "(GMT+08:00) Singapore" => "Asia/Singapore",
266             "(GMT+08:00) Taipei" => "Asia/Taipei",
267             "(GMT+08:00) Perth" => "Australia/Perth",
268             "(GMT+09:00) Irkutsk" => "Asia/Irkutsk",
269             "(GMT+08:00) Ulaan Bataar" => "Asia/Ulaanbaatar",
270             "(GMT+09:00) Seoul" => "Asia/Seoul",
271             "(GMT+09:00) Osaka" => "Asia/Tokyo",
272             "(GMT+09:00) Sapporo" => "Asia/Tokyo",
273             "(GMT+09:00) Tokyo" => "Asia/Tokyo",
274             "(GMT+10:00) Yakutsk" => "Asia/Yakutsk",
275             "(GMT+09:30) Darwin" => "Australia/Darwin",
276             "(GMT+09:30) Adelaide" => "Australia/Adelaide",
277             "(GMT+10:00) Canberra" => "Australia/Canberra",
278             "(GMT+10:00) Melbourne" => "Australia/Melbourne",
279             "(GMT+10:00) Sydney" => "Australia/Sydney",
280             "(GMT+10:00) Brisbane" => "Australia/Brisbane",
281             "(GMT+10:00) Hobart" => "Australia/Hobart",
282             "(GMT+11:00) Vladivostok" => "Asia/Vladivostok",
283             "(GMT+10:00) Guam" => "Pacific/Guam",
284             "(GMT+10:00) Port Moresby" => "Pacific/Port_Moresby",
285             "(GMT+12:00) Magadan" => "Asia/Magadan",
286             "(GMT+12:00) Solomon Is." => "+1100",
287             "(GMT+11:00) New Caledonia" => "+1100",
288             "(GMT+12:00) Fiji" => "Pacific/Fiji",
289             "(GMT+12:00) Kamchatka" => "Asia/Kamchatka",
290             "(GMT+12:00) Marshall Is." => "Pacific/Majuro",
291             "(GMT+12:00) Auckland" => "Pacific/Auckland",
292             "(GMT+12:00) Pacific/Auckland" => "Pacific/Auckland",
293             "(GMT+12:00) Wellington" => "Pacific/Auckland",
294             "(GMT+13:00) Nuku'alofa" => "Pacific/Tongatapu",
295             "(GMT+13:00) Tokelau Is." => "Pacific/Fakaofo",
296             "(GMT+13:00) Samoa" => "Pacific/Apia",
297            
298             "(GMT-10:00) Pacific/Honolulu" => "Pacific/Honolulu",
299             "(GMT-08:00) America/Los_Angeles" => "America/Los_Angeles",
300             "(GMT-08:00) America/Vancouver" => "America/Vancouver",
301             "(GMT-07:00) America/Denver" => "America/Denver",
302             "(GMT-07:00) America/Phoenix" => "America/Phoenix",
303             "(GMT-06:00) America/Chicago" => "America/Chicago",
304             "(GMT-05:00) America/New_York" => "America/New_York",
305             "(GMT-05:00) America/Toronto" => "America/Toronto",
306             "(GMT-05:00) America/Montreal" => "America/Montreal",
307             "(GMT-03:00) America/Montevideo" => "America/Montevideo",
308             "(GMT+00:00) Europe/London" => "Europe/London",
309             "(GMT+01:00) Europe/Madrid" => "Europe/Madrid",
310             "(GMT+01:00) Europe/Oslo" => "Europe/Oslo",
311             "(GMT+01:00) Europe/Stockholm" => "Europe/Stockholm",
312             "(GMT+05:00) Asia/Karachi" => "Asia/Karachi",
313             "(GMT+05:30) Asia/Calcutta" => "Asia/Calcutta",
314             "(GMT+09:30) Australia/South" => "Australia/South",
315             "(GMT+10:00) Australia/NSW" => "Australia/NSW",
316             "(GMT+10:00) Australia/Queensland" => "Australia/Queensland",
317             "(GMT+10:00) Australia/Victoria" => "Australia/Victoria",
318            
319             "(GMT-03:00) Montevideo" => "America/Montevideo",
320             "(GMT+02:00) Kaliningrad" => "Europe/Kaliningrad",
321             "(GMT+03:00) Moscow" => "Europe/Moscow",
322             "(GMT+03:00) St. Petersburg" => "Europe/Moscow",
323             "(GMT+03:00) Volgograd" => "Europe/Volgograd",
324             "(GMT+04:00) Samara" => "Europe/Samara",
325             "(GMT+05:00) Ekaterinburg" => "Asia/Yekaterinburg",
326             "(GMT+06:00) Novosibirsk" => "Asia/Novosibirsk",
327             "(GMT+06:00) Urumqi" => "Asia/Urumqi",
328             "(GMT+07:00) Krasnoyarsk" => "Asia/Krasnoyarsk",
329             "(GMT+08:00) Irkutsk" => "Asia/Irkutsk",
330             "(GMT+08:00) Ulaanbaatar" => "Asia/Ulaanbaatar",
331             "(GMT+09:00) Yakutsk" => "Asia/Yakutsk",
332             "(GMT+10:00) Magadan" => "Asia/Magadan",
333             "(GMT+10:00) Vladivostok" => "Asia/Vladivostok",
334             "(GMT+11:00) Solomon Is." => "Pacific/Guadalcanal",
335             "(GMT+11:00) Srednekolymsk" => "Asia/Srednekolymsk",
336             "(GMT+12:45) Chatham Is." => "Pacific/Chatham"
337             );
338             my %to_shopify_timezones = reverse(%from_shopify_timezones);
339              
340 0     0     sub timezone_mapping { return \%to_shopify_timezones; }
341 0     0     sub shopify_timezones { return keys(%from_shopify_timezones); }
342              
343             sub to_shopify {
344 0     0     my $dttz = $_[1];
345 0 0         return undef unless $dttz;
346 0           my $mapping = $to_shopify_timezones{$dttz->name};
347 0 0         $mapping = "(GMT+00:00) UTC" unless $mapping;
348 0           return $mapping;
349             }
350              
351             sub from_shopify {
352 0     0     my $dttz = $_[1];
353 0 0         return undef unless $dttz;
354 0           my $mapping = $from_shopify_timezones{$dttz};
355 0 0         $mapping = "UTC" unless $mapping;
356 0           return DateTime::TimeZone->new(name => $mapping);
357             }
358              
359             sub generate {
360 0     0     my @timezones = keys(%from_shopify_timezones);
361 0           return $timezones[int(rand(@timezones))];
362             }
363              
364             package WWW::Shopify::Field::Timezone::IANA;
365 1     1   406 use parent 'WWW::Shopify::Field';
  1         1  
  1         3  
366              
367 0     0     sub sql_type { return "varchar(255)"; }
368             sub to_shopify {
369 0     0     my $dttz = $_[1];
370 0 0         return undef unless $dttz;
371 0           return $dttz->name;
372             }
373              
374             sub from_shopify {
375 0     0     my $dttz = $_[1];
376 0 0         return undef unless $dttz;
377 0           return DateTime::TimeZone->new(name => $dttz);
378             }
379              
380             sub generate {
381 0     0     my @timezones = values(%WWW::Shopify::Field::Timezone::from_shopify_timezones);
382 0           return $timezones[int(rand(@timezones))];
383             }
384              
385              
386              
387             package WWW::Shopify::Field::Currency;
388 1     1   154 use parent 'WWW::Shopify::Field';
  1         1  
  1         2  
389 0     0     sub sql_type { return "varchar(255)"; }
390 0 0   0     sub generate($) { return rand() < 0.5 ? "USD" : "CAD"; }
391              
392             package WWW::Shopify::Field::Money;
393 1     1   75 use parent 'WWW::Shopify::Field';
  1         1  
  1         2  
394 1     1   38 use String::Numeric qw(is_float);
  1         1  
  1         129  
395 0     0     sub sql_type { return "decimal(10,2)"; }
396 0     0     sub generate($) { return sprintf("%.2f", rand(500)); }
397 0 0   0     sub validate($) { return undef unless $_[1] =~ m/\s*\$?\s*$/; return is_float($`); }
  0            
398 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
399              
400             package WWW::Shopify::Field::Money::USD;
401 1     1   4 use parent -norequire, 'WWW::Shopify::Field::Money';
  1         1  
  1         3  
402              
403             package WWW::Shopify::Field::Date;
404 1     1   33 use parent 'WWW::Shopify::Field';
  1         1  
  1         2  
405 1     1   775 use DateTime;
  1         77456  
  1         511  
406 0     0     sub sql_type { return 'datetime'; }
407             sub to_shopify {
408 0     0     my $dt = $_[1];
409 0 0         return undef unless $dt;
410 0 0         if (ref($dt) eq "DateTime") {
411 0           my $t = $dt->strftime('%Y-%m-%dT%H:%M:%S%z');
412 0           $t =~ s/(\d\d)$/:$1/;
413 0           return $t;
414             }
415 0 0         die new WWW::Shopify::Exception($_[0]->name . ": " . $dt) unless $dt =~ m/([\d-]+)\s*T?\s*([\d:]+)/;
416 0           return "$1T$2";
417             }
418             sub from_shopify {
419 0     0     my $dt;
420 0 0         return undef unless $_[1];
421 0           my @abbrvs = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
422 0           my $abbrvs_reg = join("|", @abbrvs);
423 0 0         if ($_[1] =~ m/(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)([+-]\d+):(\d+)/) {
    0          
    0          
424 0           $dt = DateTime->new(
425             year => $1,
426             month => $2,
427             day => $3,
428             hour => $4,
429             minute => $5,
430             second => $6,
431             time_zone => $7 . $8,
432             );
433             }
434             elsif ($_[1] =~ m/(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)/) {
435 0           $dt = DateTime->new(
436             year => $1,
437             month => $2,
438             day => $3,
439             hour => $4,
440             minute => $5,
441             second => $6,
442             );
443             }
444             elsif ($_[1] =~ m/(\d+):(\d+):(\d+) ($abbrvs_reg) (\d+), (\d+)/) {
445 0           my %types = map { $abbrvs[$_] => ($_+1) } 0..$#abbrvs;
  0            
446             $dt = DateTime->new(
447             hour => $1,
448             minute => $2,
449             second => $3,
450            
451             year => $6,
452 0           month => $types{$4},
453             day => $5,
454             );
455             }
456             else {
457 0 0         die new WWW::Shopify::Exception("Unable to parse date " . $_[0]->name . " " . $_[1]) unless $_[1] =~ m/(\d+)-(\d+)-(\d+)/;
458 0           $dt = DateTime->new(
459             year => $1,
460             month => $2,
461             day => $3
462             );
463             }
464 0           return $dt;
465             }
466 0     0     sub validate($) { return scalar($_[1] =~ m/(\d+-\d+-\d+)T?(\d+:\d+:\d+)/); }
467              
468             sub generate($) {
469 0 0   0     my %hash = $_[1] ? %{$_[1]} : @{$_[0]->{arguments}};
  0            
  0            
470 0 0         $hash{min} = '2010-01-01 00:00:00' unless $hash{min};
471 0 0         $hash{max} = 'now' unless $hash{max};
472 0           my $date = ::rand_datetime(%hash);
473 0           return $date;
474             }
475 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUANTITATIVE; }
476              
477             # Freeform datastructure. Meaning we convert it to a JSON hash, but we don't do any further processing at all.
478             package WWW::Shopify::Field::Freeform;
479 1     1   7 use parent 'WWW::Shopify::Field';
  1         1  
  1         7  
480 0     0     sub sql_type { return "text"; }
481 0     0     sub generate { return {}; }
482 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUALITATIVE; }
483 0   0 0     sub validate { return !defined $_[1] || (ref($_[1]) && ref($_[1]) eq "HASH"); }
484 0     0     sub to_shopify { return $_[1]; }
485 0     0     sub from_shopify { return $_[1]; }
486              
487             package WWW::Shopify::Field::Freeform::Array;
488 1     1   131 use parent 'WWW::Shopify::Field';
  1         2  
  1         2  
489 0     0     sub sql_type { return "text"; }
490 0     0     sub generate { return []; }
491 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUALITATIVE; }
492 0   0 0     sub validate { return !defined $_[1] || (ref($_[1]) && ref($_[1]) eq "ARRAY"); }
493 0     0     sub to_shopify { return $_[1]; }
494 0     0     sub from_shopify { return $_[1]; }
495              
496             package WWW::Shopify::Field::Freeform::Hash;
497 1     1   120 use parent 'WWW::Shopify::Field';
  1         1  
  1         5  
498 0     0     sub sql_type { return "text"; }
499 0     0     sub generate { return {}; }
500 0     0     sub data_type { return WWW::Shopify::Field::TYPE_QUALITATIVE; }
501 0   0 0     sub validate { return !defined $_[1] || (ref($_[1]) && ref($_[1]) eq "HASH"); }
502 0     0     sub to_shopify { return $_[1]; }
503 0     0     sub from_shopify { return $_[1]; }
504              
505             1;