mysql tests
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / SQLMaker / DateOps.pm
CommitLineData
c173ce76 1package DBIx::Class::SQLMaker::DateOps;
2
3use base qw/
4 Class::Accessor::Grouped
5/;
6__PACKAGE__->mk_group_accessors (simple => qw/datetime_parser/);
7use Carp::Clan qw/^DBIx::Class|^SQL::Abstract|^Try::Tiny/;
8use Sub::Name 'subname';
9
10sub _where_op_CONVERT_DATETIME {
11 my $self = shift;
12 my ($op, $rhs) = splice @_, -2;
13 croak "-$op takes a DateTime only" unless ref $rhs && $rhs->isa('DateTime');
14
15 # in case we are called as a top level special op (no '=')
16 my $lhs = shift;
17
18 $rhs = $self->datetime_parser->format_datetime($rhs);
19
20 my @bind = [
21 ($lhs || $self->{_nested_func_lhs} || undef),
22 $rhs
23 ];
24
25 return $lhs
26 ? (
27 $self->_convert($self->_quote($lhs)) . ' = ' . $self->_convert('?'),
28 @bind
29 )
30 : (
31 $self->_convert('?'),
32 @bind
33 )
34 ;
35}
36
37sub _unsupported_date_extraction {
38 "date part extraction not supported for part \"$_[1]\" with database \"$_[2]\""
39}
40
41sub _unsupported_date_adding {
42 "date part adding not supported for part \"$_[1]\" with database \"$_[2]\""
43}
44
45sub _unsupported_date_diff {
46 "date diff not supported for part \"$_[1]\" with database \"$_[2]\""
47}
48
49sub _datetime_sql { die 'date part extraction not implemented for this database' }
50
51sub _datetime_diff_sql { die 'date diffing not implemented for this database' }
52sub _datetime_add_sql { die 'date adding not implemented for this database' }
53
54sub _where_op_GET_DATETIME {
55 my ($self) = @_;
56
57 my ($k, $op, $vals);
58
59 if (@_ == 3) {
60 $op = $_[1];
61 $vals = $_[2];
62 $k = '';
63 } elsif (@_ == 4) {
64 $k = $_[1];
65 $op = $_[2];
66 $vals = $_[3];
67 }
68
69 croak 'args to -dt_get must be an arrayref' unless ref $vals eq 'ARRAY';
464a9709 70 croak 'first arg to -dt_get must be a scalar or ARRAY ref' unless !ref $vals->[0] || ref $vals->[0] eq 'ARRAY';
c173ce76 71
72 my $part = $vals->[0];
73 my $val = $vals->[1];
74
75 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
76 SCALAR => sub {
77 return ($self->_convert('?'), $self->_bindtype($k, $val) );
78 },
79 SCALARREF => sub {
80 return $$val;
81 },
82 ARRAYREFREF => sub {
83 my ($sql, @bind) = @$$val;
84 $self->_assert_bindval_matches_bindtype(@bind);
85 return ($sql, @bind);
86 },
87 HASHREF => sub {
88 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
89 $self->$method('', $val);
90 }
91 });
92
464a9709 93 if (!ref $part) {
94 return $self->_datetime_sql($part, $sql), @bind;
95 } elsif (ref $part eq 'ARRAY' ) {
96 return ( join ', ', map { $self->_datetime_sql($_, $sql) } @$part ), (@bind) x @$part;
97 }
c173ce76 98}
99
fcaf47ee 100for my $part (qw(month year hour minute second)) {
c173ce76 101 no strict 'refs';
102 my $name = '_where_op_GET_DATETIME_' . uc($part);
103 *{$name} = subname "DBIx::Class::SQLMaker::DateOps::$name", sub {
104 my $self = shift;
105 my ($op, $rhs) = splice @_, -2;
106
107 my $lhs = shift;
108
109 return $self->_where_op_GET_DATETIME($op, $lhs, [$part, $rhs])
110 }
111}
112
fcaf47ee 113sub _where_op_GET_DATETIME_DAY {
114 my $self = shift;
115 my ($op, $rhs) = splice @_, -2;
116
117 my $lhs = shift;
118
455edaef 119 # we use day_of_month instead of plain day internally
120 # because some databases also support day_of_week and day_of_year
fcaf47ee 121 return $self->_where_op_GET_DATETIME($op, $lhs, [day_of_month => $rhs])
122}
123
c173ce76 124sub _where_op_DATETIME_NOW {
125 my ($self) = @_;
126
127 my ($k, $op, $vals);
128
129 if (@_ == 3) {
130 $op = $_[1];
131 $vals = $_[2];
132 $k = '';
133 } elsif (@_ == 4) {
134 $k = $_[1];
135 $op = $_[2];
136 $vals = $_[3];
137 }
138
139 croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
140 if (!exists $vals->[0]) {
141 return $self->_datetime_now_sql()
142 } elsif ($vals->[0] eq 'system') {
143 require DateTime;
144 return $self->_where_op_CONVERT_DATETIME('dt', DateTime->now);
145 } else {
146 croak "first arg to -$op must be a 'system' or non-existant"
147 }
148}
149
150sub _reorder_add_datetime_vars {
151 my ($self, $amount, $date) = @_;
152
153 return ($amount, $date);
154}
155
156sub _where_op_ADD_DATETIME {
157 my ($self) = @_;
158
159 my ($k, $op, $vals);
160
161 if (@_ == 3) {
162 $op = $_[1];
163 $vals = $_[2];
164 $k = '';
165 } elsif (@_ == 4) {
166 $k = $_[1];
167 $op = $_[2];
168 $vals = $_[3];
169 }
170
171 croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
172 croak "first arg to -$op must be a scalar" unless !ref $vals->[0];
173 croak "-$op must have two more arguments" unless scalar @$vals == 3;
174
175 my ($part, @rest) = @$vals;
176
177 my $placeholder = $self->_convert('?');
178
179 my (@all_sql, @all_bind);
180 foreach my $val ($self->_reorder_add_datetime_vars(@rest)) {
181 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
182 SCALAR => sub {
183 return ($placeholder, $self->_bindtype($k, $val) );
184 },
185 SCALARREF => sub {
186 return $$val;
187 },
188 ARRAYREFREF => sub {
189 my ($sql, @bind) = @$$val;
190 $self->_assert_bindval_matches_bindtype(@bind);
191 return ($sql, @bind);
192 },
193 HASHREF => sub {
194 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
195 $self->$method('', $val);
196 }
197 });
198 push @all_sql, $sql;
199 push @all_bind, @bind;
200 }
201
202 return $self->_datetime_add_sql($part, $all_sql[0], $all_sql[1]), @all_bind
203}
204
f94672f9 205sub _reorder_diff_datetime_vars {
206 my ($self, $d1, $d2) = @_;
207
208 return ($d1, $d2);
209}
210
c173ce76 211sub _where_op_DIFF_DATETIME {
212 my ($self) = @_;
213
214 my ($k, $op, $vals);
215
216 if (@_ == 3) {
217 $op = $_[1];
218 $vals = $_[2];
219 $k = '';
220 } elsif (@_ == 4) {
221 $k = $_[1];
222 $op = $_[2];
223 $vals = $_[3];
224 }
225
226 croak 'args to -dt_diff must be an arrayref' unless ref $vals eq 'ARRAY';
227 croak 'first arg to -dt_diff must be a scalar' unless !ref $vals->[0];
228 croak '-dt_diff must have two more arguments' unless scalar @$vals == 3;
229
230 my ($part, @val) = @$vals;
231 my $placeholder = $self->_convert('?');
232
f94672f9 233 @val = $self->_reorder_diff_datetime_vars(@val);
c173ce76 234 my (@all_sql, @all_bind);
235 foreach my $val (@val) {
236 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
237 SCALAR => sub {
238 return ($placeholder, $self->_bindtype($k, $val) );
239 },
240 SCALARREF => sub {
241 return $$val;
242 },
243 ARRAYREFREF => sub {
244 my ($sql, @bind) = @$$val;
245 $self->_assert_bindval_matches_bindtype(@bind);
246 return ($sql, @bind);
247 },
248 HASHREF => sub {
249 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
250 $self->$method('', $val);
251 }
252 });
253 push @all_sql, $sql;
254 push @all_bind, @bind;
255 }
256
257 return $self->_datetime_diff_sql($part, $all_sql[0], $all_sql[1]), @all_bind
258}
259
2601;