add -dt_get => [\@parts, ...]
[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
119 return $self->_where_op_GET_DATETIME($op, $lhs, [day_of_month => $rhs])
120}
121
c173ce76 122sub _where_op_DATETIME_NOW {
123 my ($self) = @_;
124
125 my ($k, $op, $vals);
126
127 if (@_ == 3) {
128 $op = $_[1];
129 $vals = $_[2];
130 $k = '';
131 } elsif (@_ == 4) {
132 $k = $_[1];
133 $op = $_[2];
134 $vals = $_[3];
135 }
136
137 croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
138 if (!exists $vals->[0]) {
139 return $self->_datetime_now_sql()
140 } elsif ($vals->[0] eq 'system') {
141 require DateTime;
142 return $self->_where_op_CONVERT_DATETIME('dt', DateTime->now);
143 } else {
144 croak "first arg to -$op must be a 'system' or non-existant"
145 }
146}
147
148sub _reorder_add_datetime_vars {
149 my ($self, $amount, $date) = @_;
150
151 return ($amount, $date);
152}
153
154sub _where_op_ADD_DATETIME {
155 my ($self) = @_;
156
157 my ($k, $op, $vals);
158
159 if (@_ == 3) {
160 $op = $_[1];
161 $vals = $_[2];
162 $k = '';
163 } elsif (@_ == 4) {
164 $k = $_[1];
165 $op = $_[2];
166 $vals = $_[3];
167 }
168
169 croak "args to -$op must be an arrayref" unless ref $vals eq 'ARRAY';
170 croak "first arg to -$op must be a scalar" unless !ref $vals->[0];
171 croak "-$op must have two more arguments" unless scalar @$vals == 3;
172
173 my ($part, @rest) = @$vals;
174
175 my $placeholder = $self->_convert('?');
176
177 my (@all_sql, @all_bind);
178 foreach my $val ($self->_reorder_add_datetime_vars(@rest)) {
179 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
180 SCALAR => sub {
181 return ($placeholder, $self->_bindtype($k, $val) );
182 },
183 SCALARREF => sub {
184 return $$val;
185 },
186 ARRAYREFREF => sub {
187 my ($sql, @bind) = @$$val;
188 $self->_assert_bindval_matches_bindtype(@bind);
189 return ($sql, @bind);
190 },
191 HASHREF => sub {
192 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
193 $self->$method('', $val);
194 }
195 });
196 push @all_sql, $sql;
197 push @all_bind, @bind;
198 }
199
200 return $self->_datetime_add_sql($part, $all_sql[0], $all_sql[1]), @all_bind
201}
202
f94672f9 203sub _reorder_diff_datetime_vars {
204 my ($self, $d1, $d2) = @_;
205
206 return ($d1, $d2);
207}
208
c173ce76 209sub _where_op_DIFF_DATETIME {
210 my ($self) = @_;
211
212 my ($k, $op, $vals);
213
214 if (@_ == 3) {
215 $op = $_[1];
216 $vals = $_[2];
217 $k = '';
218 } elsif (@_ == 4) {
219 $k = $_[1];
220 $op = $_[2];
221 $vals = $_[3];
222 }
223
224 croak 'args to -dt_diff must be an arrayref' unless ref $vals eq 'ARRAY';
225 croak 'first arg to -dt_diff must be a scalar' unless !ref $vals->[0];
226 croak '-dt_diff must have two more arguments' unless scalar @$vals == 3;
227
228 my ($part, @val) = @$vals;
229 my $placeholder = $self->_convert('?');
230
f94672f9 231 @val = $self->_reorder_diff_datetime_vars(@val);
c173ce76 232 my (@all_sql, @all_bind);
233 foreach my $val (@val) {
234 my ($sql, @bind) = $self->_SWITCH_refkind($val, {
235 SCALAR => sub {
236 return ($placeholder, $self->_bindtype($k, $val) );
237 },
238 SCALARREF => sub {
239 return $$val;
240 },
241 ARRAYREFREF => sub {
242 my ($sql, @bind) = @$$val;
243 $self->_assert_bindval_matches_bindtype(@bind);
244 return ($sql, @bind);
245 },
246 HASHREF => sub {
247 my $method = $self->_METHOD_FOR_refkind("_where_hashpair", $val);
248 $self->$method('', $val);
249 }
250 });
251 push @all_sql, $sql;
252 push @all_bind, @bind;
253 }
254
255 return $self->_datetime_diff_sql($part, $all_sql[0], $all_sql[1]), @all_bind
256}
257
2581;