Skip to content

Commit

Permalink
Add search by address URI and tests for this
Browse files Browse the repository at this point in the history
  • Loading branch information
autarch committed Aug 19, 2012
1 parent d2c3784 commit d7f4c50
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 39 deletions.
25 changes: 25 additions & 0 deletions lib/VegGuide/Controller/Base.pm
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,31 @@ sub _params_from_path_query {
entity => $entity,
);

$c->detach();

return;
}
}

{
my $type
= 'application/vnd.vegguide.org-error+json; charset=UTF-8; version=0.0.1';

sub _rest_error_response {
my $self = shift;
my $c = shift;
my $message = shift;
my $status = shift;

my $meth = 'status_' . $status;

$self->$meth(
$c,
message => $message,
);

$c->detach();

return;
}
}
Expand Down
162 changes: 123 additions & 39 deletions lib/VegGuide/Controller/Search.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use strict;
use warnings;
use namespace::autoclean;

use URI::Escape qw( uri_escape );
use VegGuide::Geocoder;
use VegGuide::Search::Vendor::ByLatLong;
use VegGuide::Search::Vendor::ByName;
use VegGuide::SiteURI qw( static_uri );
Expand Down Expand Up @@ -38,58 +40,140 @@ with 'VegGuide::Role::Controller::Search';

$self->_set_search_in_stash( $c, %SearchConfig );

my $search = $c->stash()->{search};
$self->_set_cursor_params($c);

my $limit = $c->request()->parameters()->{limit} || 200;
my $page = $c->request()->parameters()->{page} || 1;
$search->set_cursor_params(
limit => $limit,
page => $page,
);
my $search = $c->stash()->{search};

my $path
= '/search/by-lat-long/'
. $search->latitude() . ','
. $search->longitude();

my %rest = (
entry_count => $search->count(),
uri => static_uri(
path => $path,
query => {
distance => $search->distance(),
unit => $search->unit(),
},
with_host => 1,
)
);
. uri_escape( $search->latitude() ) . ','
. uri_escape( $search->longitude() );

my $vendors = $search->vendors();
while ( my $vendor = $vendors->next() ) {
my $entry_rest = $vendor->rest_data( include_related => 0 );
my $distance = $vendor->distance_from(
latitude => $search->latitude(),
longitude => $search->longitude(),
unit => $search->unit(),
);
$self->_search_rest_response( $c, $search, $path );

return;
}
}

{
my %SearchConfig = (
captured_path_position => 1,
search_class => 'VegGuide::Search::Vendor::ByLatLong',
);

sub by_address :
LocalRegex('^by-address/([^/]+)(?:/filter(?:/(.*)))?$')
: ActionClass('+VegGuide::Action::REST') { }

sub by_address_GET : Private {
my $self = shift;
my $c = shift;

my $with_units = $distance . ' ' . $search->unit();
$with_units .= 's' unless $distance == 1;
my $address = $c->request()->captures()->[0];

$entry_rest->{distance} = $with_units;
my $country = ( split /,\s*/, $address )[-1];
my $geocoder = VegGuide::Geocoder->new( country => $country );
$geocoder ||= VegGuide::Geocoder->new( country => 'USA' );

push @{ $rest{entries} }, $entry_rest;
my $result = $geocoder->geocode_full_address($address);

$rest{region}
||= $vendor->location()->rest_data( include_related => 0 );
unless ($result) {
$self->_rest_error_response(
$c,
"The address your provided ($address) could not be resolved to a ltitude and longitude.",
'not_found',
);

return;
}

$self->_rest_response(
$c,
'search',
\%rest,
my $unit = $geocoder->country() eq 'USA' ? 'mile' : 'km';

my %config = %SearchConfig;
$config{extra_params} = sub {
return (
latitude => $result->latitude(),
longitude => $result->longitude(),
address => $address,
unit => $unit,
);
};

$self->_set_search_in_stash( $c, %config );

$self->_set_cursor_params($c);

my $search = $c->stash()->{search};

my $path = '/search/by-address/' . uri_escape( $search->address() );

$self->_search_rest_response( $c, $search, $path );

return;
}
}

sub _set_cursor_params {
my $self = shift;
my $c = shift;

my $search = $c->stash()->{search};

my $limit = $c->request()->parameters()->{limit} || 50;
$limit = 100 if $limit > 100;

my $page = $c->request()->parameters()->{page} || 1;
$search->set_cursor_params(
limit => $limit,
page => $page,
);

return;
}

sub _search_rest_response {
my $self = shift;
my $c = shift;
my $search = shift;
my $path = shift;

my %rest = (
entry_count => $search->count(),
uri => static_uri(
path => $path,
query => {
distance => $search->distance(),
unit => $search->unit(),
},
with_host => 1,
)
);

my $vendors = $search->vendors();
while ( my $vendor = $vendors->next() ) {
my $entry_rest = $vendor->rest_data( include_related => 0 );
my $distance = $vendor->distance_from(
latitude => $search->latitude(),
longitude => $search->longitude(),
unit => $search->unit(),
);

my $with_units = $distance . ' ' . $search->unit();
$with_units .= 's' unless $distance == 1;

$entry_rest->{distance} = $with_units;

push @{ $rest{entries} }, $entry_rest;

$rest{region}
||= $vendor->location()->rest_data( include_related => 0 );
}

$self->_rest_response(
$c,
'search',
\%rest,
);
}

__PACKAGE__->meta()->make_immutable();
Expand Down
119 changes: 119 additions & 0 deletions t/rest-api/Search.t
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,131 @@ use_test_database();
'got 5 entries back'
);

is(
$search->{entries}[0]{name},
'Chiang Mai Thai',
'first entry returned is X'
);

is(
$search->{entry_count},
23,
'entry_count is all of the entries returned'
);
}

{
my $response = request(
rest_request(
GET => '/search/by-lat-long/44.9479791,-93.2935778?distance=1;limit=5;page=2'
)
);

is( $response->code(), '200', 'got a 200 response' );

is(
$response->header('Content-Type'),
'application/vnd.vegguide.org-search+json; charset=UTF-8; version=0.0.1',
'got the right RESTful content type'
);

my $search = json_ok($response);

is(
scalar @{ $search->{entries} },
5,
'got 5 entries back'
);

is(
$search->{entries}[0]{name},
'Galactic Pizza',
'first entry returned is Galactic Pizza (second page of results)'
);

is(
$search->{entry_count},
23,
'entry_count is all of the entries returned'
);
}

{
no warnings 'redefine';
local *VegGuide::Geocoder::geocode_full_address = sub {
return undef;
};

my $response = request(
rest_request(
GET => '/search/by-address/not-found?distance=1'
)
);

is( $response->code(), '404', 'got a 404 response for bad address' );
}

{
no warnings 'redefine';
local *VegGuide::Geocoder::geocode_full_address = sub {
return VegGuide::Geocoder::Result->new(
{
Point => { coordinates => [ -93.2935778, 44.9479791 ] },
address => 'good address',
},
);
};

my $response = request(
rest_request(
GET => '/search/by-address/good-address?distance=1'
)
);

is( $response->code(), '200', 'got a 200 response for good address' );

my $search = json_ok($response);

my $uri = URI->new( $search->{uri} );
is(
$uri->path(),
'/search/by-address/good-address',
'got expected uri path for search'
);

is_deeply(
$search->{region},
{
is_country => 0,
entries_uri => path_to_uri('/region/13/entries'),
name => 'Twin Cities',
time_zone => 'America/Chicago',
uri => path_to_uri('/region/13'),
entry_count => 116,
},
'got Twin Cities region back for search'
);

is(
scalar @{ $search->{entries} },
23,
'got 23 entries back'
);

is(
$search->{entry_count},
23,
'entry_count is same as the number of entries returned'
);

my $entry = $search->{entries}[0];

is(
$entry->{distance},
'0.2 miles',
'entry data has a distance key with the expected value'
);
}

done_testing();

0 comments on commit d7f4c50

Please sign in to comment.