File Coverage

blib/lib/WebAPI/DBIC/RouteMaker.pm
Criterion Covered Total %
statement 27 83 32.5
branch 0 24 0.0
condition 0 13 0.0
subroutine 9 15 60.0
pod 0 5 0.0
total 36 140 25.7


line stmt bran cond sub pod time code
1             package WebAPI::DBIC::RouteMaker;
2             $WebAPI::DBIC::RouteMaker::VERSION = '0.003002';
3              
4 2     2   4854091 use Moo;
  2         43220  
  2         16  
5              
6 2     2   2690 use Module::Runtime qw(use_module);
  2         3  
  2         44  
7 2     2   1056 use Sub::Util qw(subname);
  2         517  
  2         175  
8 2     2   9 use Scalar::Util qw(blessed);
  2         2  
  2         208  
9 2     2   10 use Carp qw(croak confess);
  2         2  
  2         157  
10 2     2   950 use Devel::Dwarn;
  2         20324  
  2         15  
11              
12 2     2   1654 use namespace::clean -except => [qw(meta)];
  2         24340  
  2         19  
13 2     2   1941 use MooX::StrictConstructor;
  2         22420  
  2         11  
14              
15 2     2   37684 use WebAPI::DBIC::Route;
  2         4  
  2         20  
16              
17              
18             has schema => (is => 'rw');
19              
20             has resource_class_for_item => (is => 'ro', default => 'WebAPI::DBIC::Resource::GenericItem');
21             has resource_class_for_item_invoke => (is => 'ro', default => 'WebAPI::DBIC::Resource::GenericItemInvoke');
22             has resource_class_for_set => (is => 'ro', default => 'WebAPI::DBIC::Resource::GenericSet');
23             has resource_class_for_set_invoke => (is => 'ro', default => 'WebAPI::DBIC::Resource::GenericSetInvoke');
24             has resource_default_args => (is => 'ro', default => sub { {} });
25              
26             has type_namer => (
27             is => 'ro',
28             default => sub {
29             require WebAPI::DBIC::TypeNamer;
30             return WebAPI::DBIC::TypeNamer->new
31             },
32             );
33              
34              
35             sub _qr_names {
36 0 0   0     my $names_r = join "|", map { quotemeta $_ } @_ or confess "panic";
  0            
37 0           return qr/^(?:$names_r)$/x;
38             }
39              
40              
41             sub make_routes_for_resultset {
42 0     0 0   my ($self, $path, $set, %opts) = @_;
43              
44 0 0         if ($ENV{WEBAPI_DBIC_DEBUG}) {
45 0           warn sprintf "Auto routes for /%s => %s\n",
46             $path, $set->result_class;
47             }
48              
49 0           my @routes;
50              
51 0           push @routes, $self->make_routes_for_set($path, $set, {
52             invokable_methods => delete($opts{invokeable_methods_on_set}),
53             });
54              
55 0           push @routes, $self->make_routes_for_item($path, $set, {
56             invokable_methods => delete($opts{invokeable_methods_on_item})
57             });
58              
59 0 0         croak "Unrecognized options: @{[ keys %opts ]}"
  0            
60             if %opts;
61              
62 0           return @routes;
63             }
64              
65              
66             sub make_routes_for_item {
67 0     0 0   my ($self, $path, $set, $opts) = @_;
68 0   0       $opts ||= {};
69 0           my $methods = $opts->{invokable_methods};
70              
71 0           use_module $self->resource_class_for_item;
72 0           my $id_unique_constraint_name = $self->resource_class_for_item->id_unique_constraint_name;
73 0           my $key_fields = { $set->result_source->unique_constraints }->{ $id_unique_constraint_name };
74              
75 0 0         unless ($key_fields) {
76 0           warn sprintf "/%s/:id route skipped because %s has no '$id_unique_constraint_name' constraint defined\n",
77             $path, $set->result_class;
78 0           return;
79             }
80              
81             # id fields have sequential numeric names
82             # so .../:1 for a resource with a single key field
83             # and .../:1/:2/:3 etc for a resource with multiple key fields
84 0           my $item_path_spec = join "/", map { ":$_" } 1 .. @$key_fields;
  0            
85              
86 0           my @routes;
87              
88 0           push @routes, WebAPI::DBIC::Route->new( # item
89             path => "$path/$item_path_spec",
90             resource_class => $self->resource_class_for_item,
91             resource_args => {
92 0           %{ $self->resource_default_args },
93             set => $set,
94             type_namer => $self->type_namer,
95             },
96             );
97              
98             # XXX temporary hack just for testing
99 0 0         push @$methods, 'get_column'
100             if $set->result_class eq 'TestSchema::Result::Artist';
101              
102 0           push @routes, WebAPI::DBIC::Route->new( # method call on item
103             path => "$path/$item_path_spec/invoke/:method",
104             validations => { method => _qr_names(@$methods), },
105             resource_class => $self->resource_class_for_item_invoke,
106             resource_args => {
107 0 0 0       %{ $self->resource_default_args },
108             set => $set,
109             type_namer => $self->type_namer,
110             },
111             ) if $methods && @$methods;
112              
113 0           return @routes;
114             }
115              
116              
117             sub make_routes_for_set {
118 0     0 0   my ($self, $path, $set, $opts) = @_;
119 0   0       $opts ||= {};
120 0           my $methods = $opts->{invokable_methods};
121              
122 0           my @routes;
123            
124 0           push @routes, WebAPI::DBIC::Route->new(
125             path => $path,
126             resource_class => $self->resource_class_for_set,
127             resource_args => {
128 0           %{ $self->resource_default_args },
129             set => $set,
130             type_namer => $self->type_namer,
131             },
132             );
133              
134 0           push @routes, WebAPI::DBIC::Route->new( # method call on set
135             path => "$path/invoke/:method",
136             validations => { method => _qr_names(@$methods) },
137             resource_class => $self->resource_class_for_set_invoke,
138             resource_args => {
139 0 0 0       %{ $self->resource_default_args },
140             set => $set,
141             type_namer => $self->type_namer,
142             },
143             ) if $methods && @$methods;
144              
145 0           return @routes;
146             }
147              
148              
149             sub make_root_route {
150 0     0 0   my $self = shift;
151 0           my $root_route = WebAPI::DBIC::Route->new(
152             path => '',
153             resource_class => 'WebAPI::DBIC::Resource::GenericRoot',
154             resource_args => {
155 0           %{ $self->resource_default_args },
156             type_namer => $self->type_namer,
157             },
158             );
159 0           return $root_route;
160             }
161              
162              
163              
164             sub make_routes_for {
165 0     0 0   my ($self, $route_spec) = @_;
166              
167 0           my %opts;
168              
169 0 0         if (ref $route_spec eq 'HASH') {
170             # invokeable_methods_on_item => undef,
171             # invokeable_methods_on_set => undef,
172 0           %opts = %$route_spec;
173 0           $route_spec = delete $opts{set};
174             }
175              
176 0 0         if (not ref $route_spec) {
    0          
177 0 0         my $schema = $self->schema
178             or croak "Can't convert '$route_spec' to a resultset because schema isn't set in $self";
179 0           $route_spec = $schema->resultset($route_spec);
180             }
181             elsif ($route_spec->does('WebAPI::DBIC::Resource::Role::Route')) {
182 0           return $route_spec; # is already a route
183             }
184              
185 0 0 0       unless (blessed $route_spec and $route_spec->isa('DBIx::Class::ResultSet')) {
186 0           croak "Don't know how to convert '$route_spec' into to a DBIx::Class::ResultSet or WebAPI::DBIC::Resource::Role::Route";
187             }
188              
189 0           my $type_name = $self->type_namer->type_name_for_resultset($route_spec);
190              
191 0           return $self->make_routes_for_resultset($type_name, $route_spec, %opts);
192             }
193              
194              
195             1;
196              
197             __END__
198              
199             =pod
200              
201             =encoding UTF-8
202              
203             =head1 NAME
204              
205             WebAPI::DBIC::RouteMaker
206              
207             =head1 VERSION
208              
209             version 0.003002
210              
211             =head1 NAME
212              
213             WebAPI::DBIC::RouteMaker - Make routes for resultsets
214              
215             =head1 AUTHOR
216              
217             Tim Bunce <Tim.Bunce@pobox.com>
218              
219             =head1 COPYRIGHT AND LICENSE
220              
221             This software is copyright (c) 2015 by Tim Bunce.
222              
223             This is free software; you can redistribute it and/or modify it under
224             the same terms as the Perl 5 programming language system itself.
225              
226             =cut