moved -dt_diff (year) test after the other -dt_diff tests
[dbsrgits/DBIx-Class.git] / t / sqlmaker / op_dt.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6
7 use lib qw(t/lib);
8 use DBIC::SqlMakerTest;
9 use DateTime;
10 use DBIx::Class::SQLMaker::MSSQL;
11 use Try::Tiny;
12 use Data::Dumper::Concise;
13
14 use DBICTest;
15
16 my %dbs_to_test = (
17    sqlite   => 1,
18    mssql    => 0,
19    postgres => 1,
20    oracle   => 1,
21 );
22
23 my %schema = (
24    sqlite => DBICTest->init_schema( no_populate => 1 ),
25    mssql => do {
26       my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
27       if ($dsn && $user) {
28          my $s = DBICTest::Schema->connect($dsn, $user, $pass);
29          try { $s->storage->ensure_connected };
30
31          $s->storage->dbh_do (sub {
32              my ($storage, $dbh) = @_;
33              eval { $dbh->do("DROP TABLE event") };
34              $dbh->do(<<'SQL');
35 CREATE TABLE event (
36    id INT IDENTITY NOT NULL,
37    starts_at DATE NOT NULL,
38    created_on DATETIME NOT NULL,
39    varchar_date VARCHAR(20),
40    varchar_datetime VARCHAR(20),
41    skip_inflation DATETIME,
42    ts_without_tz DATETIME,
43
44    primary key(id)
45 )
46 SQL
47         $dbs_to_test{mssql} = 1;
48 });
49 $s;
50       } else {
51          DBICTest->init_schema( no_deploy=> 1, storage_type => '::DBI::MSSQL' )
52       }
53    },
54    ## copypasta'd for great justice
55    postgres =>  do {
56       my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_POSTGRES_${_}" } qw/DSN USER PASS/};
57       if ($dsn && $user) {
58          my $s = DBICTest::Schema->connect($dsn, $user, $pass);
59          try { $s->storage->ensure_connected };
60
61          $s->storage->dbh_do (sub {
62              my ($storage, $dbh) = @_;
63              eval { $dbh->do("DROP TABLE event") };
64              $dbh->do(<<'SQL');
65 CREATE TABLE event (
66    id SERIAL NOT NULL PRIMARY KEY,
67    starts_at DATE NOT NULL,
68    created_on TIMESTAMP NOT NULL,
69    varchar_date VARCHAR(20),
70    varchar_datetime VARCHAR(20),
71    skip_inflation TIMESTAMP,
72    ts_without_tz TIMESTAMP WITHOUT TIME ZONE
73 )
74 SQL
75         $dbs_to_test{postgres} = 1;
76 });
77 $s;
78       } else {
79          DBICTest->init_schema( no_deploy=> 1, storage_type => '::DBI::Pg' )
80       }
81    },
82    oracle =>  do {
83       my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_ORA_${_}" } qw/DSN USER PASS/};
84       if ($dsn && $user) {
85          my $s = DBICTest::Schema->connect($dsn, $user, $pass, { on_connect_call => 'datetime_setup' });
86          try { $s->storage->ensure_connected };
87
88          $s->storage->dbh_do (sub {
89              my ($storage, $dbh) = @_;
90              eval { $dbh->do("DROP TRIGGER trq_event_id") };
91              eval { $dbh->do("DROP SEQUENCE sq_event_id") };
92              eval { $dbh->do("DROP TABLE event") };
93              $dbh->do('CREATE SEQUENCE sq_event_id');
94              $dbh->do(<<'SQL');
95 CREATE TABLE event (
96    id NUMBER NOT NULL,
97    starts_at DATE NOT NULL,
98    created_on TIMESTAMP NOT NULL,
99    varchar_date VARCHAR(20),
100    varchar_datetime VARCHAR(20),
101    skip_inflation TIMESTAMP,
102    ts_without_tz TIMESTAMP,
103    CONSTRAINT PK_EVENT PRIMARY KEY (id)
104 )
105 SQL
106              $dbh->do(<<'SQL');
107 CREATE TRIGGER trg_event_id
108 BEFORE INSERT ON event
109 FOR EACH ROW WHEN (
110   new.id IS NULL OR new.id = 0
111 )
112 BEGIN
113   SELECT sq_event_id.nextval
114   INTO :new.id
115   FROM dual;
116   END;
117 SQL
118         $dbs_to_test{oracle} = 1;
119 });
120 $s;
121       } else {
122          DBICTest->init_schema( no_deploy=> 1, storage_type => '::DBI::Oracle', on_connect_call => 'datetime_setup' )
123       }
124    },
125 );
126
127 my %rs = map { $_ => $schema{$_}->resultset('Event') } keys %schema;
128
129 $rs{sqlite}->populate([
130  [qw(starts_at created_on skip_inflation)],
131  ['2010-12-12', '2010-12-14 12:12:12', '2019-12-12 12:12:12'],
132  ['2010-12-12', '2011-12-14 12:12:12', '2011-12-12 12:12:12'],
133 ]);
134
135 $rs{mssql}->populate([
136  [qw(starts_at created_on skip_inflation)],
137  ['2010-12-12', '2010-12-14 12:12:12.000', '2019-12-12 12:12:12.000'],
138  ['2010-12-12', '2011-12-14 12:12:12.000', '2011-12-12 12:12:12.000'],
139 ]) if $schema{mssql}->storage->connected;
140
141 $rs{postgres}->populate([
142  [qw(starts_at created_on skip_inflation)],
143  ['2010-12-12', '2010-12-14 12:12:12', '2019-12-12 12:12:12'],
144  ['2010-12-12', '2011-12-14 12:12:12', '2011-12-12 12:12:12'],
145 ]) if $schema{postgres}->storage->connected;
146
147 $rs{oracle}->populate([
148  [qw(starts_at created_on skip_inflation)],
149  ['2010-12-12', '2010-12-14 12:12:12', '2019-12-12 12:12:12'],
150  ['2010-12-12', '2011-12-14 12:12:12', '2011-12-12 12:12:12'],
151 ]) if $schema{oracle}->storage->connected;
152
153 my $date = DateTime->new(
154    year => 2010,
155    month => 12,
156    day   => 14,
157    hour  => 12,
158    minute => 12,
159    second => 12,
160 );
161
162 sub hri_thing {
163    return {
164       starts_at => $_[0],
165       created_on => $_[1],
166       skip_inflation => $_[2]
167    }
168 }
169
170 my $date2 = $date->clone->set_day(16);
171
172 ## test format:
173 ##   search => { dbic_search_code/params }
174 ##   rdbms_name => literal_sql
175 my @tests = (
176 ## -dt-now tests
177   {
178     search => { 'me.created_on' => { -dt => $date } },
179     sqlite => {
180       select => 'me.starts_at, me.created_on, me.skip_inflation',
181       where  => 'me.created_on = ?',
182       bind   => [[ 'me.created_on', '2010-12-14 12:12:12' ]],
183       hri    => [hri_thing('2010-12-12', '2010-12-14 12:12:12', '2019-12-12 12:12:12')],
184     },
185     mssql => {
186       select => 'me.starts_at, me.created_on, me.skip_inflation',
187       where  => 'me.created_on = ?',
188       bind   => [[ 'me.created_on', '2010-12-14 12:12:12.000' ]],
189       hri    => [hri_thing('2010-12-12', '2010-12-14 12:12:12.000', '2019-12-12 12:12:12.000')],
190     },
191     postgres => {
192       select => 'me.starts_at, me.created_on, me.skip_inflation',
193       where  => 'me.created_on = ?',
194       bind   => [[ 'me.created_on', '2010-12-14 12:12:12' ]],
195       hri    => [hri_thing('2010-12-12', '2010-12-14 12:12:12', '2019-12-12 12:12:12')],
196     },
197     oracle => {
198       select => 'me.starts_at, me.created_on, me.skip_inflation',
199       where  => 'me.created_on = ?',
200       bind   => [[ 'me.created_on', '2010-12-14 12:12:12' ]],
201       hri    => [hri_thing('2010-12-12 00:00:00', '2010-12-14 12:12:12.000000', '2019-12-12 12:12:12.000000')],
202     },
203     msg => '-dt_now works',
204   },
205 ## -dt_year tests
206   {
207     search => { 'me.id' => 1 },
208     select => [ [ -dt_year => { -ident => 'me.created_on' } ] ],
209     as     => [ 'year' ],
210     mssql => {
211       select => "DATEPART(year, me.created_on)",
212       where => "me.id = ?",
213       bind   => [['me.id' => 1 ]],
214       hri    => [{ year => 2010 }],
215     },
216     sqlite => {
217       select => "STRFTIME('%Y', me.created_on)",
218       where => "me.id = ?",
219       bind   => [['me.id' => 1 ]],
220       hri    => [{ year => 2010 }],
221     },
222     postgres => {
223       select => "EXTRACT(year FROM me.created_on)",
224       where => "me.id = ?",
225       bind   => [['me.id' => 1 ]],
226       hri    => [{ year => 2010 }],
227     },
228     oracle => {
229       select => "EXTRACT(year FROM me.created_on)",
230       where => "me.id = ?",
231       bind   => [['me.id' => 1 ]],
232       hri    => [{ year => 2010 }],
233     },
234     msg    => '-dt_year works',
235   },
236 ## -dt_get(year, month) tests
237   {
238     search => { 'me.id' => 1 },
239     select => [ [ -dt_get => [[qw(year month)], { -ident => 'me.created_on' }] ] ],
240     as     => [ qw(year month) ],
241     mssql => {
242       select => "DATEPART(year, me.created_on), DATEPART(month, me.created_on)",
243       where => "me.id = ?",
244       bind   => [['me.id' => 1 ]],
245       hri    => [{ year => 2010, month => 12 }],
246     },
247     sqlite => {
248       select => "STRFTIME('%Y', me.created_on), STRFTIME('%m', me.created_on)",
249       where => "me.id = ?",
250       bind   => [['me.id' => 1 ]],
251       hri    => [{ year => 2010, month => 12 }],
252     },
253     postgres => {
254       select => "EXTRACT(year FROM me.created_on), EXTRACT(month FROM me.created_on)",
255       where => "me.id = ?",
256       bind   => [['me.id' => 1 ]],
257       hri    => [{ year => 2010, month => 12 }],
258     },
259     oracle => {
260       select => "EXTRACT(year FROM me.created_on), EXTRACT(month FROM me.created_on)",
261       where => "me.id = ?",
262       bind   => [['me.id' => 1 ]],
263       hri    => [{ year => 2010, month => 12 }],
264     },
265     msg    => '-dt_get (year, month) works',
266   },
267 ## -dt_month tests
268   {
269     search => { 'me.id' => 1 },
270     select   => [ [ -dt_month => { -ident => 'me.created_on' } ] ],
271     as       => [ 'month' ],
272     sqlite => {
273       select   => "STRFTIME('%m', me.created_on)",
274       where => "me.id = ?",
275       bind   => [['me.id' => 1 ]],
276       hri    => [{ month => 12 }],
277     },
278     mssql => {
279       select => "DATEPART(month, me.created_on)",
280       where => "me.id = ?",
281       bind   => [['me.id' => 1 ]],
282       hri    => [{ month => 12 }],
283     },
284     postgres => {
285       select => "EXTRACT(month FROM me.created_on)",
286       where => "me.id = ?",
287       bind   => [['me.id' => 1 ]],
288       hri    => [{ month => 12 }],
289     },
290     oracle => {
291       select => "EXTRACT(month FROM me.created_on)",
292       where => "me.id = ?",
293       bind   => [['me.id' => 1 ]],
294       hri    => [{ month => 12 }],
295     },
296     msg    => '-dt_month works',
297   },
298 ## -dt_day tests
299   {
300     search => { 'me.id' => 1 },
301     select   => [ [ -dt_day => { -ident => 'me.created_on' } ] ],
302     as       => [ 'day' ],
303     sqlite => {
304       select   => "STRFTIME('%d', me.created_on)",
305       where => "me.id = ?",
306       bind   => [['me.id' => 1 ]],
307       hri    => [{ day => 14 }],
308     },
309     mssql => {
310       select => "DATEPART(day, me.created_on)",
311       where => "me.id = ?",
312       bind   => [['me.id' => 1 ]],
313       hri    => [{ day => 14 }],
314     },
315     postgres => {
316       select => "EXTRACT(day FROM me.created_on)",
317       where => "me.id = ?",
318       bind   => [['me.id' => 1 ]],
319       hri    => [{ day => 14 }],
320     },
321     oracle => {
322       select => "EXTRACT(day FROM me.created_on)",
323       where => "me.id = ?",
324       bind   => [['me.id' => 1 ]],
325       hri    => [{ day => 14 }],
326     },
327     msg    => '-dt_day works',
328   },
329 ## -dt_hour tests
330   {
331     search => { 'me.id' => 1 },
332     select   => [ [ -dt_hour => { -ident => 'me.created_on' } ] ],
333     as       => [ 'hour' ],
334     sqlite => {
335       select   => "STRFTIME('%H', me.created_on)",
336       where => "me.id = ?",
337       bind   => [['me.id' => 1 ]],
338       hri    => [{ hour => 12 }],
339     },
340     mssql => {
341       select => "DATEPART(hour, me.created_on)",
342       where => "me.id = ?",
343       bind   => [['me.id' => 1 ]],
344       hri    => [{ hour => 12 }],
345     },
346     postgres => {
347       select => "EXTRACT(hour FROM me.created_on)",
348       where => "me.id = ?",
349       bind   => [['me.id' => 1 ]],
350       hri    => [{ hour => 12 }],
351     },
352     oracle => {
353       select => "EXTRACT(hour FROM me.created_on)",
354       where => "me.id = ?",
355       bind   => [['me.id' => 1 ]],
356       hri    => [{ hour => 12 }],
357     },
358     msg    => '-dt_hour works',
359   },
360 ## -dt_minute tests
361   {
362     search => { 'me.id' => 1 },
363     select   => [ [ -dt_minute => { -ident => 'me.created_on' } ] ],
364     as       => [ 'minute' ],
365     sqlite => {
366       select   => "STRFTIME('%M', me.created_on)",
367       where => "me.id = ?",
368       bind   => [['me.id' => 1 ]],
369       hri    => [{ minute => 12 }],
370     },
371     mssql => {
372       select => "DATEPART(minute, me.created_on)",
373       where => "me.id = ?",
374       bind   => [['me.id' => 1 ]],
375       hri    => [{ minute => 12 }],
376     },
377     postgres => {
378       select => "EXTRACT(minute FROM me.created_on)",
379       where => "me.id = ?",
380       bind   => [['me.id' => 1 ]],
381       hri    => [{ minute => 12 }],
382     },
383     oracle => {
384       select => "EXTRACT(minute FROM me.created_on)",
385       where => "me.id = ?",
386       bind   => [['me.id' => 1 ]],
387       hri    => [{ minute => 12 }],
388     },
389     msg    => '-dt_minute works',
390   },
391 ## -dt_second tests
392   {
393     search => { 'me.id' => 1 },
394     select   => [ [ -dt_second => { -ident => 'me.created_on' } ] ],
395     as       => [ 'second' ],
396     sqlite => {
397       select   => "STRFTIME('%S', me.created_on)",
398       where => "me.id = ?",
399       bind   => [['me.id' => 1 ]],
400       hri    => [{ second => 12 }],
401     },
402     mssql => {
403       select => "DATEPART(second, me.created_on)",
404       where => "me.id = ?",
405       bind   => [['me.id' => 1 ]],
406       hri    => [{ second => 12 }],
407     },
408     postgres => {
409       select => "EXTRACT(second FROM me.created_on)",
410       where => "me.id = ?",
411       bind   => [['me.id' => 1 ]],
412       hri    => [{ second => 12 }],
413     },
414     oracle => {
415       select => "EXTRACT(second FROM me.created_on)",
416       where => "me.id = ?",
417       bind   => [['me.id' => 1 ]],
418       hri    => [{ second => 12 }],
419     },
420     msg    => '-dt_second works',
421   },
422 ## -dt_diff(second) tests
423   {
424     search => { 'me.id' => 2 },
425     select   => [ [ -dt_diff => [second => { -ident => 'me.created_on' }, \'me.skip_inflation' ] ] ],
426     as => [ 'sec_diff' ],
427     sqlite => {
428       select   => "(STRFTIME('%s', me.created_on) - STRFTIME('%s', me.skip_inflation))",
429       where => "me.id = ?",
430       bind   => [['me.id' => 2 ]],
431       hri => [{ sec_diff => 2*24*60*60 }],
432     },
433     mssql => {
434       select   => "DATEDIFF(second, me.skip_inflation, me.created_on)",
435       where => "me.id = ?",
436       bind   => [['me.id' => 2 ]],
437       hri => [{ sec_diff => 2*24*60*60 }],
438     },
439     postgres => {
440       select   => "EXTRACT(epoch FROM (me.created_on::timestamp with time zone - me.skip_inflation::timestamp with time zone))",
441       where => "me.id = ?",
442       bind   => [['me.id' => 2 ]],
443       hri => [{ sec_diff => 2*24*60*60 }],
444     },
445     oracle => {
446       select   => "TRUNC(MONTHS_BETWEEN(me.created_on, me.skip_inflation) * 31 * 24 * 60 * 60)",
447       where => "me.id = ?",
448       bind   => [['me.id' => 2 ]],
449       hri => [{ sec_diff => 2*24*60*60 }],
450     },
451     msg    => '-dt_diff (second) works',
452   },
453
454 # -dt_diff(day) tests
455   {
456     search => { 'me.id' => 2 },
457     select   => [ [ -dt_diff => [day => { -ident => 'me.created_on' }, \'me.skip_inflation' ] ] ],
458     as => [ 'day_diff' ],
459     sqlite => {
460       select   => "(JULIANDAY(me.created_on) - JULIANDAY(me.skip_inflation))",
461       where => "me.id = ?",
462       bind   => [['me.id' => 2 ]],
463       hri => [{ day_diff => 2 }],
464     },
465     mssql => {
466       select   => "DATEDIFF(dayofyear, me.skip_inflation, me.created_on)",
467       where => "me.id = ?",
468       bind   => [['me.id' => 2 ]],
469       hri => [{ day_diff => 2 }],
470     },
471     postgres => {
472       select   => "EXTRACT(DAY FROM (me.created_on::timestamp with time zone - me.skip_inflation::timestamp with time zone))",
473       where => "me.id = ?",
474       bind   => [['me.id' => 2 ]],
475       hri => [{ day_diff => 2 }],
476     },
477     oracle => {
478       select   => "TRUNC(MONTHS_BETWEEN(me.created_on, me.skip_inflation) * 31)",
479       where => "me.id = ?",
480       bind   => [['me.id' => 2 ]],
481       hri => [{ day_diff => 2 }],
482     },
483     msg    => '-dt_diff (day) works',
484   },
485
486   {
487     msg => '-dt_diff (year) works',
488     search => { 'me.id' => 2 },
489     select   => [ [ -dt_diff => [year => \'me.starts_at', { -ident => 'me.created_on' } ] ] ],
490     as       => [ 'year' ],
491     sqlite => {
492       exception_like => qr/date diff not supported for part "year" with database "SQLite"/,
493     },
494     mssql => {
495       select   => "DATEDIFF(year, me.created_on, me.starts_at)",
496       where => "me.id = ?",
497       bind   => [['me.id', 2]],
498       hri    => [{ year => -1 }],
499     },
500     oracle => {
501       select   => "TRUNC(MONTHS_BETWEEN(me.starts_at, me.created_on) / 12)",
502       where => "me.id = ?",
503       bind   => [['me.id', 2]],
504       hri    => [{ year => -1 }],
505     },
506   },
507
508   {
509     msg    => '-dt_add (year) works',
510     search => { 'me.id' => 2 },
511     select   => [ [ -dt_add => [year => 3, { -ident => 'me.created_on' } ] ] ],
512     as   => [ 'date' ],
513     sqlite => {
514       select => "(datetime(me.created_on, ? || ' years'))",
515       where => "me.id = ?",
516       bind   => [['', 3], ['me.id' => 2 ]],
517       hri    => [{ date => '2014-12-14 12:12:12' }],
518     },
519     mssql => {
520       select => "(DATEADD(year, ?, me.created_on))",
521       where => "me.id = ?",
522       bind   => [['', 3], ['me.id' => 2 ]],
523       hri    => [{ date => '2014-12-14 12:12:12.000' }],
524       skip   => 'need working bindtypes',
525     },
526     oracle => {
527       select => "(me.created_on + NUMTOYMINTERVAL(?, 'year'))",
528       where => "me.id = ?",
529       bind   => [['', 3], ['me.id' => 2 ]],
530       hri    => [{ date => '2014-12-14 12:12:12.000000000' }],
531     },
532   },
533
534   {
535     msg    => '-dt_add (month) works',
536     search => { 'me.id' => 2 },
537     select   => [ [ -dt_add => [month => 3, { -ident => 'me.created_on' } ] ] ],
538     as   => [ 'date' ],
539     sqlite => {
540       select => "(datetime(me.created_on, ? || ' months'))",
541       where => "me.id = ?",
542       bind   => [['', 3], ['me.id' => 2 ]],
543       hri    => [{ date => '2012-03-14 12:12:12' }],
544     },
545     mssql => {
546       select => "(DATEADD(month, ?, me.created_on))",
547       where => "me.id = ?",
548       bind   => [['', 3], ['me.id' => 2 ]],
549       hri    => [{ date => '2012-03-14 12:12:12.000' }],
550       skip   => 'need working bindtypes',
551     },
552     oracle => {
553       select => "(me.created_on + NUMTOYMINTERVAL(?, 'month'))",
554       where => "me.id = ?",
555       bind   => [['', 3], ['me.id' => 2 ]],
556       hri    => [{ date => '2012-03-14 12:12:12.000000000' }],
557     },
558   },
559
560   {
561     msg    => '-dt_add (day) works',
562     search => { 'me.id' => 2 },
563     select   => [ [ -dt_add => [day => 3, { -ident => 'me.created_on' } ] ] ],
564     as   => [ 'date' ],
565     sqlite => {
566       select => "(datetime(me.created_on, ? || ' days'))",
567       where => "me.id = ?",
568       bind   => [['', 3], ['me.id' => 2 ]],
569       hri    => [{ date => '2011-12-17 12:12:12' }],
570     },
571     mssql => {
572       select => "(DATEADD(dayofyear, ?, me.created_on))",
573       where => "me.id = ?",
574       bind   => [['', 3], ['me.id' => 2 ]],
575       hri    => [{ date => '2011-12-17 12:12:12.000' }],
576       skip   => 'need working bindtypes',
577     },
578     oracle => {
579       select => "(me.created_on + NUMTODSINTERVAL(?, 'day'))",
580       where => "me.id = ?",
581       bind   => [['', 3], ['me.id' => 2 ]],
582       hri    => [{ date => '2011-12-17 12:12:12.000000000' }],
583     },
584   },
585
586   {
587     msg    => '-dt_add (hour) works',
588     search => { 'me.id' => 2 },
589     select   => [ [ -dt_add => [hour => 3, { -ident => 'me.created_on' } ] ] ],
590     as   => [ 'date' ],
591     sqlite => {
592       select => "(datetime(me.created_on, ? || ' hours'))",
593       where => "me.id = ?",
594       bind   => [['', 3], ['me.id' => 2 ]],
595       hri    => [{ date => '2011-12-14 15:12:12' }],
596     },
597     mssql => {
598       select => "(DATEADD(hour, ?, me.created_on))",
599       where => "me.id = ?",
600       bind   => [['', 3], ['me.id' => 2 ]],
601       hri    => [{ date => '2011-12-14 15:12:12.000' }],
602       skip   => 'need working bindtypes',
603     },
604     oracle => {
605       select => "(me.created_on + NUMTODSINTERVAL(?, 'hour'))",
606       where => "me.id = ?",
607       bind   => [['', 3], ['me.id' => 2 ]],
608       hri    => [{ date => '2011-12-14 15:12:12.000000000' }],
609     },
610   },
611
612   {
613     msg    => '-dt_add (minute) works',
614     search => { 'me.id' => 2 },
615     select   => [ [ -dt_add => [minute => 3, { -ident => 'me.created_on' } ] ] ],
616     as   => [ 'date' ],
617     sqlite => {
618       select => "(datetime(me.created_on, ? || ' minutes'))",
619       where => "me.id = ?",
620       bind   => [['', 3], ['me.id' => 2 ]],
621       hri    => [{ date => '2011-12-14 12:15:12' }],
622     },
623     mssql => {
624       select => "(DATEADD(minute, ?, me.created_on))",
625       where => "me.id = ?",
626       bind   => [['', 3], ['me.id' => 2 ]],
627       hri    => [{ date => '2011-12-14 12:15:12.000' }],
628       skip   => 'need working bindtypes',
629     },
630     oracle => {
631       select => "(me.created_on + NUMTODSINTERVAL(?, 'minute'))",
632       where => "me.id = ?",
633       bind   => [['', 3], ['me.id' => 2 ]],
634       hri    => [{ date => '2011-12-14 12:15:12.000000000' }],
635     },
636   },
637
638   {
639     msg    => '-dt_add (second) works',
640     search => { 'me.id' => 2 },
641     select   => [ [ -dt_add => [second => 3, { -ident => 'me.created_on' } ] ] ],
642     as   => [ 'date' ],
643     sqlite => {
644       select => "(datetime(me.created_on, ? || ' seconds'))",
645       where => "me.id = ?",
646       bind   => [['', 3], ['me.id' => 2 ]],
647       hri    => [{ date => '2011-12-14 12:12:15' }],
648     },
649     mssql => {
650       select => "(DATEADD(second, ?, me.created_on))",
651       where => "me.id = ?",
652       bind   => [['', 3], ['me.id' => 2 ]],
653       hri    => [{ date => '2011-12-14 12:12:15.000' }],
654       skip   => 'need working bindtypes',
655     },
656     oracle => {
657       select => "(me.created_on + NUMTODSINTERVAL(?, 'second'))",
658       where => "me.id = ?",
659       bind   => [['', 3], ['me.id' => 2 ]],
660       hri    => [{ date => '2011-12-14 12:12:15.000000000' }],
661     },
662   },
663
664   {
665     msg    => 'nested -dt_add works',
666     search => { 'me.id' => 2 },
667     select   => [ [ -dt_add => [second => 3, { -dt_add => [ day => 1, { -ident => 'me.created_on' } ] } ] ] ],
668     as       => [ 'date' ],
669     sqlite => {
670       select   => "(datetime((datetime(me.created_on, ? || ' days')), ? || ' seconds'))",
671       where => "me.id = ?",
672       bind   => [['', 1], [ '', 3 ], ['me.id', 2]],
673       hri    => [{ date => '2011-12-15 12:12:15' }],
674     },
675     mssql => {
676       select => "(DATEADD(second, ?, (DATEADD(dayofyear, ?, me.created_on))))",
677       where => "me.id = ?",
678       bind   => [['', 3], [ '', 1 ], ['me.id', 2]],
679       hri    => [{ date => '2011-12-15 12:12:15.000' }],
680       skip   => 'need working bindtypes',
681     },
682     oracle => {
683       select => "((me.created_on + NUMTODSINTERVAL(?, 'day')) + NUMTODSINTERVAL(?, 'second'))",
684       where => "me.id = ?",
685       bind   => [['', 1], [ '', 3 ], ['me.id', 2]],
686       hri    => [{ date => '2011-12-15 12:12:15.000000000' }],
687     },
688   },
689 );
690
691 for my $t (@tests) {
692
693   DB_TEST:
694   for my $db (keys %rs) {
695      my $db_test = $t->{$db};
696      next DB_TEST unless $db_test;
697
698      my ($r, $my_rs);
699
700      my $cref = sub {
701        my $stuff = {
702          ( exists $t->{select}
703            ? ( select => $t->{select}, as => $t->{as} )
704            : ( columns => [qw(starts_at created_on skip_inflation)] )
705          )
706        };
707        $my_rs = $rs{$db}->search($t->{search}, $stuff);
708        $r = $my_rs->as_query
709      };
710
711      if ($db_test->{exception_like}) {
712        throws_ok(
713          sub { $cref->() },
714          $db_test->{exception_like},
715          "throws the expected exception ($db_test->{exception_like})",
716        );
717      } else {
718        if ($db_test->{warning_like}) {
719          warning_like(
720            sub { $cref->() },
721            $db_test->{warning_like},
722            "issues the expected warning ($db_test->{warning_like})"
723          );
724        }
725        else {
726          $cref->();
727        }
728        is_same_sql_bind(
729          $r,
730          "(SELECT $db_test->{select} FROM event me WHERE $db_test->{where})",
731          $db_test->{bind},
732          ($t->{msg} ? "$t->{msg} ($db)" : ())
733        );
734
735        SKIP: {
736        if (my $hri = $db_test->{hri}) {
737           skip "Cannot test database we are not connected to ($db)", 1 unless $dbs_to_test{$db};
738           skip $db_test->{skip} . " ($db)", 1 if $db_test->{skip};
739
740           my $msg = ($t->{msg} ? "$t->{msg} ($db actually pulls expected data)" : '');
741           try {
742              my $got = [ $my_rs->hri_dump->all ];
743              my $success = is_deeply $got, $hri, $msg;
744              unless ($success) {
745                 warn "$db: $t->{msg} got:      " . Dumper $got;
746                 warn "$db: $t->{msg} expected: " . Dumper $hri;
747              }
748           } catch {
749              ok 0, $msg . " $_";
750           }
751         } }
752      }
753   }
754 }
755
756 done_testing;