Retire DBIC/SqlMakerTest.pm now that SQLA::Test provides the same function
[dbsrgits/DBIx-Class.git] / t / sqlmaker / limit_dialects / rownum.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5
6 use lib qw(t/lib);
7 use DBICTest ':DiffSQL';
8 use DBIx::Class::SQLMaker::LimitDialects;
9
10 my ($TOTAL, $OFFSET, $ROWS) = (
11    DBIx::Class::SQLMaker::LimitDialects->__total_bindtype,
12    DBIx::Class::SQLMaker::LimitDialects->__offset_bindtype,
13    DBIx::Class::SQLMaker::LimitDialects->__rows_bindtype,
14 );
15
16 my $s = DBICTest->init_schema (no_deploy => 1, );
17 $s->storage->sql_maker->limit_dialect ('RowNum');
18
19 my $rs = $s->resultset ('CD')->search({ id => 1 });
20
21 # important for a test below, never traversed
22 $rs->result_source->add_relationship(
23   ends_with_me => 'DBICTest::Schema::Artist', sub {}
24 );
25
26
27 my $where_bind = [ { dbic_colname => 'id' }, 1 ];
28
29 for my $test_set (
30   {
31     name => 'Rownum subsel aliasing works correctly',
32     rs => $rs->search_rs(undef, {
33       rows => 1,
34       offset => 3,
35       columns => [
36         { id => 'foo.id' },
37         { 'artist.id' => 'bar.id' },
38         { bleh => \'TO_CHAR (foo.womble, "blah")' },
39       ]
40     }),
41     sql => '(
42       SELECT id, artist__id, bleh
43       FROM (
44         SELECT id, artist__id, bleh, ROWNUM AS rownum__index
45         FROM (
46           SELECT foo.id AS id, bar.id AS artist__id, TO_CHAR (foo.womble, "blah") AS bleh
47             FROM cd me
48           WHERE id = ?
49         ) me
50       ) me WHERE rownum__index BETWEEN ? AND ?
51     )',
52     binds => [
53       $where_bind,
54       [ $OFFSET => 4 ],
55       [ $TOTAL => 4 ],
56     ],
57   }, {
58     name => 'Rownum subsel aliasing works correctly with unique order_by',
59     rs => $rs->search_rs(undef, {
60       rows => 1,
61       offset => 3,
62       columns => [
63         { id => 'foo.id' },
64         { 'artist.id' => 'bar.id' },
65         { bleh => \'TO_CHAR (foo.womble, "blah")' },
66       ],
67       order_by => [qw( artist title )],
68     }),
69     sql => '(
70       SELECT id, artist__id, bleh
71       FROM (
72         SELECT id, artist__id, bleh, ROWNUM AS rownum__index
73         FROM (
74           SELECT foo.id AS id, bar.id AS artist__id, TO_CHAR(foo.womble, "blah") AS bleh
75             FROM cd me
76           WHERE id = ?
77           ORDER BY artist, title
78         ) me
79         WHERE ROWNUM <= ?
80       ) me
81       WHERE rownum__index >= ?
82     )',
83     binds => [
84       $where_bind,
85       [ $TOTAL => 4 ],
86       [ $OFFSET => 4 ],
87     ],
88   },
89  {
90     name => 'Rownum subsel aliasing works correctly with non-unique order_by',
91     rs => $rs->search_rs(undef, {
92       rows => 1,
93       offset => 3,
94       columns => [
95         { id => 'foo.id' },
96         { 'artist.id' => 'bar.id' },
97         { bleh => \'TO_CHAR (foo.womble, "blah")' },
98       ],
99       order_by => 'artist',
100     }),
101     sql => '(
102       SELECT id, artist__id, bleh
103       FROM (
104         SELECT id, artist__id, bleh, ROWNUM AS rownum__index
105         FROM (
106           SELECT foo.id AS id, bar.id AS artist__id, TO_CHAR(foo.womble, "blah") AS bleh
107             FROM cd me
108           WHERE id = ?
109           ORDER BY artist
110         ) me
111       ) me
112       WHERE rownum__index BETWEEN ? and ?
113     )',
114     binds => [
115       $where_bind,
116       [ $OFFSET => 4 ],
117       [ $TOTAL => 4 ],
118     ],
119   }, {
120     name => 'Rownum subsel aliasing #2 works correctly',
121     rs => $rs->search_rs(undef, {
122       rows => 2,
123       offset => 3,
124       columns => [
125         { id => 'foo.id' },
126         { 'ends_with_me.id' => 'ends_with_me.id' },
127       ]
128     }),
129     sql => '(
130       SELECT id, ends_with_me__id
131       FROM (
132         SELECT id, ends_with_me__id, ROWNUM AS rownum__index
133         FROM (
134           SELECT foo.id AS id, ends_with_me.id AS ends_with_me__id
135             FROM cd me
136           WHERE id = ?
137         ) me
138       ) me WHERE rownum__index BETWEEN ? AND ?
139     )',
140     binds => [
141       $where_bind,
142       [ $OFFSET => 4 ],
143       [ $TOTAL => 5 ],
144     ],
145   }, {
146     name => 'Rownum subsel aliasing #2 works correctly with unique order_by',
147     rs => $rs->search_rs(undef, {
148       rows => 2,
149       offset => 3,
150       columns => [
151         { id => 'foo.id' },
152         { 'ends_with_me.id' => 'ends_with_me.id' },
153       ],
154       order_by => [qw( year artist title )],
155     }),
156     sql => '(
157       SELECT id, ends_with_me__id
158       FROM (
159         SELECT id, ends_with_me__id, ROWNUM AS rownum__index
160         FROM (
161           SELECT foo.id AS id, ends_with_me.id AS ends_with_me__id
162             FROM cd me
163           WHERE id = ?
164           ORDER BY year, artist, title
165         ) me
166         WHERE ROWNUM <= ?
167       ) me
168       WHERE rownum__index >= ?
169     )',
170     binds => [
171       $where_bind,
172       [ $TOTAL => 5 ],
173       [ $OFFSET => 4 ],
174     ],
175   }
176 ) {
177   is_same_sql_bind(
178     $test_set->{rs}->as_query,
179     $test_set->{sql},
180     $test_set->{binds},
181     $test_set->{name});
182 }
183
184 {
185 my $subq = $s->resultset('Owners')->search({
186    'count.id' => { -ident => 'owner.id' },
187 }, { alias => 'owner' })->count_rs;
188
189 my $rs_selectas_rel = $s->resultset('BooksInLibrary')->search ({}, {
190   columns => [
191      { owner_name => 'owner.name' },
192      { owner_books => $subq->as_query },
193   ],
194   join => 'owner',
195   rows => 2,
196   offset => 3,
197 });
198
199 is_same_sql_bind(
200   $rs_selectas_rel->as_query,
201   '(
202     SELECT owner_name, owner_books
203       FROM (
204         SELECT owner_name, owner_books, ROWNUM AS rownum__index
205           FROM (
206             SELECT  owner.name AS owner_name,
207               ( SELECT COUNT( * ) FROM owners owner WHERE (count.id = owner.id)) AS owner_books
208               FROM books me
209               JOIN owners owner ON owner.id = me.owner
210             WHERE ( source = ? )
211           ) me
212       ) me
213     WHERE rownum__index BETWEEN ? AND ?
214   )',
215   [
216     [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
217       => 'Library' ],
218     [ $OFFSET => 4 ],
219     [ $TOTAL => 5 ],
220   ],
221
222   'pagination with subquery works'
223 );
224
225 }
226
227 {
228   $rs = $s->resultset('Artist')->search({}, {
229     columns => 'name',
230     offset => 1,
231     order_by => 'name',
232   });
233   local $rs->result_source->{name} = "weird \n newline/multi \t \t space containing \n table";
234
235   like (
236     ${$rs->as_query}->[0],
237     qr| weird \s \n \s newline/multi \s \t \s \t \s space \s containing \s \n \s table|x,
238     'Newlines/spaces preserved in final sql',
239   );
240 }
241
242 {
243 my $subq = $s->resultset('Owners')->search({
244    'books.owner' => { -ident => 'owner.id' },
245 }, { alias => 'owner', select => ['id'] } )->count_rs;
246
247 my $rs_selectas_rel = $s->resultset('BooksInLibrary')->search( { -exists => $subq->as_query }, { select => ['id','owner'], rows => 1 } );
248
249 is_same_sql_bind(
250   $rs_selectas_rel->as_query,
251   '(
252     SELECT me.id, me.owner FROM (
253       SELECT me.id, me.owner  FROM books me WHERE ( ( (EXISTS (SELECT COUNT( * ) FROM owners owner WHERE ( books.owner = owner.id ))) AND source = ? ) )
254     ) me
255     WHERE ROWNUM <= ?
256   )',
257   [
258     [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
259     [ $ROWS => 1 ],
260   ],
261   'Pagination with sub-query in WHERE works'
262 );
263
264 }
265
266 done_testing;