Reimplement parameter localization using a goto loop
[dbsrgits/DBIx-Class-ParameterizedJoinHack.git] / t / 00basic.t
1 use strict;
2 use warnings;
3 use lib 't/lib';
4 use Test::More;
5 use Test::Fatal;
6 use My::Schema;
7
8 unless (eval { require DBD::SQLite; 1 }) {
9     plan skip_all => 'Unable to load DBD::SQLite';
10 }
11
12 my $schema = My::Schema->connect('dbi:SQLite:dbname=:memory:');
13
14 $schema->deploy;
15
16 my $people = $schema->resultset('Person');
17
18 my $bob = $people->create({
19     name => 'Bob Testuser',
20 });
21
22 $bob->create_related(assigned_tasks => {
23     summary => 'Task A',
24     urgency => 10,
25 });
26 $bob->create_related(assigned_tasks => {
27     summary => 'Task B',
28     urgency => 20,
29 });
30 $bob->create_related(assigned_tasks => {
31     summary => 'Task C',
32     urgency => 30,
33 });
34
35 subtest 'has_many' => sub {
36
37     my $join_with_min = sub {
38         return shift->with_parameterized_join(
39             urgent_assigned_tasks => { urgency_threshold => $_[0] },
40         );
41     };
42
43     my $join_with_range = sub {
44         return shift->with_parameterized_join(
45             tasks_in_urgency_range => {
46                 min => $_[0],
47                 max => $_[1],
48             },
49         );
50     };
51
52     my $search_count = sub {
53         return scalar shift->search(
54             { 'me.name' => { -like => 'Bob%' } },
55             {
56                 '+select' => [{
57                     count => \[shift],
58                 }],
59                 '+as' => ['task_count'],
60             },
61         );
62     };
63     my $search = sub { $search_count->(shift, 'urgent_assigned_tasks.id') };
64
65     my $fetch_count = sub {
66         return shift->next->get_column('task_count');
67     };
68
69     subtest 'simple filter' => sub {
70         is $people->$join_with_min(19)->$search->$fetch_count,
71             2, 'filter min 19';
72         is $people->$join_with_min(29)->$search->$fetch_count,
73             1, 'filter min 29';
74         is $people->$join_with_min(39)->$search->$fetch_count,
75             0, 'filter min 39';
76     };
77
78     subtest 'multiple filters' => sub {
79         my $rs1 = $people->$join_with_min(19)->$search;
80         my $rs2 = $people->$join_with_min(29)->$search;
81         is $rs1->$fetch_count, 2, 'first';
82         is $rs2->$fetch_count, 1, 'second';
83     };
84
85     subtest 'overrides' => sub {
86         like exception {
87             $people
88                 ->$join_with_min(19)
89                 ->$join_with_min(29)
90                 ->$search
91                 ->$fetch_count;
92         }, qr{once.+per.+relation}i, 'throws error';
93     };
94
95     subtest 'multi parameter' => sub {
96         my $search = sub {
97             $search_count->(shift, 'tasks_in_urgency_range.id');
98         };
99         is $people->$join_with_range(10, 30)->$search->$fetch_count,
100             3, 'full range';
101     };
102
103     subtest 'multi join' => sub {
104         is $people
105             ->$join_with_min(19)
106             ->$join_with_range(10, 30)
107             ->$search
108             ->$fetch_count,
109             2*3, 'full count';
110     };
111
112     subtest 'unconstrained' => sub {
113         is $people
114             ->with_parameterized_join(unconstrained_tasks => {})
115             ->$search_count('unconstrained_tasks.id')
116             ->$fetch_count,
117             3, 'unconstrained count';
118     };
119
120     subtest 'errors' => sub {
121         like exception {
122             $people->with_parameterized_join(urgent_assigned_tasks => {})
123                 ->$search
124                 ->$fetch_count;
125         }, qr{urgent_assigned_tasks.+urgency_threshold}, 'missing parameter';
126         like exception {
127             $people->with_parameterized_join(__invalid__ => {})
128                 ->$search
129                 ->$fetch_count;
130         }, qr{__invalid__}, 'unknown relation';
131         like exception {
132             $people->with_parameterized_join(undef, {});
133         }, qr{relation.+name}i, 'missing relation name';
134         like exception {
135             $people->with_parameterized_join(foo => []);
136         }, qr{parameters.+hash.+not.+ARRAY}i, 'invalid parameters';
137         like exception {
138             $people->with_parameterized_join(foo => 23);
139         }, qr{parameters.+hash.+not.+non-reference}i, 'non ref parameters';
140     };
141
142     subtest 'declaration errors' => sub {
143         my $errors = \%My::Schema::Result::Person::ERROR;
144         like delete $errors->{no_args}, qr{Missing.+relation.+name}i,
145             'no arguments';
146         like delete $errors->{no_source}, qr{Missing.+foreign.+source}i,
147             'no foreign source';
148         like delete $errors->{no_cond}, qr{Condition.+non-ref.+value}i,
149             'no condition';
150         like delete $errors->{invalid_cond}, qr{Condition.+SCALAR}i,
151             'invalid condition';
152         like delete $errors->{undef_args}, qr{Arguments.+array.+non-ref}i,
153             'undef args';
154         like delete $errors->{invalid_args}, qr{Arguments.+array.+SCALAR}i,
155             'invalid args';
156         like delete $errors->{undef_builder}, qr{builder.+code.+non-ref}i,
157             'undef builder';
158         like delete $errors->{invalid_builder}, qr{builder.+code.+ARRAY}i,
159             'invalid builder';
160         is_deeply $errors, {}, 'no more errors';
161     };
162 };
163
164 done_testing;