Permalink
Browse files

Add search by address URI and tests for this

  • Loading branch information...
1 parent d2c3784 commit d7f4c50eb8bf1da50878a8df75f923f3ed216cff @autarch autarch committed Aug 19, 2012
Showing with 267 additions and 39 deletions.
  1. +25 −0 lib/VegGuide/Controller/Base.pm
  2. +123 −39 lib/VegGuide/Controller/Search.pm
  3. +119 −0 t/rest-api/Search.t
@@ -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;
}
}
@@ -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 );
@@ -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();
View
@@ -93,11 +93,130 @@ use_test_database();
);
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.