Compare commits
2 Commits
main
...
feat/user-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39a4f09700 | ||
|
|
de52de72c1 |
@ -44,6 +44,7 @@ func TestSearchSuccess(t *testing.T) {
|
||||
"formattedAddress": "123 Street",
|
||||
"location": {"latitude": 1.23, "longitude": 4.56},
|
||||
"rating": 4.7,
|
||||
"userRatingCount": 532,
|
||||
"priceLevel": "PRICE_LEVEL_MODERATE",
|
||||
"types": ["cafe"],
|
||||
"currentOpeningHours": {"openNow": true}
|
||||
@ -95,6 +96,9 @@ func TestSearchSuccess(t *testing.T) {
|
||||
if result.PriceLevel == nil || *result.PriceLevel != 2 {
|
||||
t.Fatalf("unexpected price level: %#v", result.PriceLevel)
|
||||
}
|
||||
if result.UserRatingCount == nil || *result.UserRatingCount != 532 {
|
||||
t.Fatalf("unexpected user rating count: %#v", result.UserRatingCount)
|
||||
}
|
||||
if result.OpenNow == nil || *result.OpenNow != true {
|
||||
t.Fatalf("unexpected openNow: %#v", result.OpenNow)
|
||||
}
|
||||
@ -287,6 +291,7 @@ func TestNearbySearchSuccess(t *testing.T) {
|
||||
"formattedAddress": "123 Street",
|
||||
"location": {"latitude": 1.23, "longitude": 4.56},
|
||||
"rating": 4.7,
|
||||
"userRatingCount": 42,
|
||||
"priceLevel": "PRICE_LEVEL_MODERATE",
|
||||
"types": ["cafe"],
|
||||
"currentOpeningHours": {"openNow": true}
|
||||
@ -312,6 +317,9 @@ func TestNearbySearchSuccess(t *testing.T) {
|
||||
if len(response.Results) != 1 {
|
||||
t.Fatalf("expected 1 result, got %d", len(response.Results))
|
||||
}
|
||||
if response.Results[0].UserRatingCount == nil || *response.Results[0].UserRatingCount != 42 {
|
||||
t.Fatalf("unexpected user rating count: %#v", response.Results[0].UserRatingCount)
|
||||
}
|
||||
if response.NextPageToken != "next" {
|
||||
t.Fatalf("unexpected token: %s", response.NextPageToken)
|
||||
}
|
||||
@ -383,6 +391,7 @@ func TestDetailsSuccess(t *testing.T) {
|
||||
"formattedAddress": "Central",
|
||||
"location": {"latitude": 10, "longitude": 20},
|
||||
"rating": 4.2,
|
||||
"userRatingCount": 1234,
|
||||
"priceLevel": "PRICE_LEVEL_FREE",
|
||||
"types": ["park"],
|
||||
"regularOpeningHours": {"weekdayDescriptions": ["Mon: 9-5"]},
|
||||
@ -405,6 +414,9 @@ func TestDetailsSuccess(t *testing.T) {
|
||||
if place.PlaceID != "place-123" {
|
||||
t.Fatalf("unexpected id: %s", place.PlaceID)
|
||||
}
|
||||
if place.UserRatingCount == nil || *place.UserRatingCount != 1234 {
|
||||
t.Fatalf("unexpected user rating count: %#v", place.UserRatingCount)
|
||||
}
|
||||
if place.OpenNow == nil || *place.OpenNow != false {
|
||||
t.Fatalf("unexpected openNow")
|
||||
}
|
||||
|
||||
29
details.go
29
details.go
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
detailsFieldMaskBase = "id,displayName,formattedAddress,location,rating,priceLevel,types,regularOpeningHours,currentOpeningHours,nationalPhoneNumber,websiteUri"
|
||||
detailsFieldMaskBase = "id,displayName,formattedAddress,location,rating,userRatingCount,priceLevel,types,regularOpeningHours,currentOpeningHours,nationalPhoneNumber,websiteUri"
|
||||
detailsFieldMaskReview = "reviews"
|
||||
detailsFieldMaskPhotos = "photos"
|
||||
)
|
||||
@ -61,18 +61,19 @@ func detailsFieldMaskForRequest(req DetailsRequest) string {
|
||||
|
||||
func mapPlaceDetails(place placeItem) PlaceDetails {
|
||||
return PlaceDetails{
|
||||
PlaceID: place.ID,
|
||||
Name: displayName(place.DisplayName),
|
||||
Address: place.FormattedAddress,
|
||||
Location: mapLatLng(place.Location),
|
||||
Rating: place.Rating,
|
||||
PriceLevel: mapPriceLevel(place.PriceLevel),
|
||||
Types: place.Types,
|
||||
Phone: place.NationalPhoneNumber,
|
||||
Website: place.WebsiteURI,
|
||||
Hours: weekdayDescriptions(place.RegularOpeningHours),
|
||||
OpenNow: openNow(place.CurrentOpeningHours),
|
||||
Reviews: mapReviews(place.Reviews),
|
||||
Photos: mapPhotos(place.Photos),
|
||||
PlaceID: place.ID,
|
||||
Name: displayName(place.DisplayName),
|
||||
Address: place.FormattedAddress,
|
||||
Location: mapLatLng(place.Location),
|
||||
Rating: place.Rating,
|
||||
UserRatingCount: place.UserRatingCount,
|
||||
PriceLevel: mapPriceLevel(place.PriceLevel),
|
||||
Types: place.Types,
|
||||
Phone: place.NationalPhoneNumber,
|
||||
Website: place.WebsiteURI,
|
||||
Hours: weekdayDescriptions(place.RegularOpeningHours),
|
||||
OpenNow: openNow(place.CurrentOpeningHours),
|
||||
Reviews: mapReviews(place.Reviews),
|
||||
Photos: mapPhotos(place.Photos),
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,7 +188,7 @@ func autocompleteSubtitle(suggestion goplaces.AutocompleteSuggestion) string {
|
||||
func writePlaceSummary(out *bytes.Buffer, color Color, place goplaces.PlaceSummary) {
|
||||
writeLine(out, color, "ID", place.PlaceID)
|
||||
writeLocation(out, color, place.Location)
|
||||
writeRating(out, color, place.Rating, place.PriceLevel)
|
||||
writeRating(out, color, place.Rating, place.UserRatingCount, place.PriceLevel)
|
||||
writeTypes(out, color, place.Types)
|
||||
writeOpenNow(out, color, place.OpenNow)
|
||||
}
|
||||
@ -206,7 +206,7 @@ func writeAutocompleteSuggestion(out *bytes.Buffer, color Color, suggestion gopl
|
||||
func writePlaceDetails(out *bytes.Buffer, color Color, place goplaces.PlaceDetails) {
|
||||
writeLine(out, color, "ID", place.PlaceID)
|
||||
writeLocation(out, color, place.Location)
|
||||
writeRating(out, color, place.Rating, place.PriceLevel)
|
||||
writeRating(out, color, place.Rating, place.UserRatingCount, place.PriceLevel)
|
||||
writeTypes(out, color, place.Types)
|
||||
writeOpenNow(out, color, place.OpenNow)
|
||||
writeLine(out, color, "Phone", place.Phone)
|
||||
@ -300,13 +300,19 @@ func writeLocation(out *bytes.Buffer, color Color, loc *goplaces.LatLng) {
|
||||
writeLine(out, color, "Location", fmt.Sprintf("%.6f, %.6f", loc.Lat, loc.Lng))
|
||||
}
|
||||
|
||||
func writeRating(out *bytes.Buffer, color Color, rating *float64, priceLevel *int) {
|
||||
if rating == nil && priceLevel == nil {
|
||||
func writeRating(out *bytes.Buffer, color Color, rating *float64, userRatingCount *int, priceLevel *int) {
|
||||
if rating == nil && userRatingCount == nil && priceLevel == nil {
|
||||
return
|
||||
}
|
||||
parts := make([]string, 0, 2)
|
||||
parts := make([]string, 0, 3)
|
||||
if rating != nil {
|
||||
parts = append(parts, fmt.Sprintf("%.1f", *rating))
|
||||
ratingStr := fmt.Sprintf("%.1f", *rating)
|
||||
if userRatingCount != nil {
|
||||
ratingStr += fmt.Sprintf(" (%d)", *userRatingCount)
|
||||
}
|
||||
parts = append(parts, ratingStr)
|
||||
} else if userRatingCount != nil {
|
||||
parts = append(parts, fmt.Sprintf("%d ratings", *userRatingCount))
|
||||
}
|
||||
if priceLevel != nil {
|
||||
parts = append(parts, fmt.Sprintf("$%d", *priceLevel))
|
||||
|
||||
@ -12,17 +12,19 @@ import (
|
||||
func TestRenderSearch(t *testing.T) {
|
||||
open := true
|
||||
level := 2
|
||||
ratingCount := 532
|
||||
response := goplaces.SearchResponse{
|
||||
Results: []goplaces.PlaceSummary{
|
||||
{
|
||||
PlaceID: "abc",
|
||||
Name: "Cafe",
|
||||
Address: "123 Street",
|
||||
Location: &goplaces.LatLng{Lat: 1, Lng: 2},
|
||||
Rating: floatPtr(4.5),
|
||||
PriceLevel: &level,
|
||||
Types: []string{"cafe", "coffee_shop"},
|
||||
OpenNow: &open,
|
||||
PlaceID: "abc",
|
||||
Name: "Cafe",
|
||||
Address: "123 Street",
|
||||
Location: &goplaces.LatLng{Lat: 1, Lng: 2},
|
||||
Rating: floatPtr(4.5),
|
||||
UserRatingCount: &ratingCount,
|
||||
PriceLevel: &level,
|
||||
Types: []string{"cafe", "coffee_shop"},
|
||||
OpenNow: &open,
|
||||
},
|
||||
},
|
||||
NextPageToken: "next",
|
||||
@ -35,6 +37,9 @@ func TestRenderSearch(t *testing.T) {
|
||||
if !strings.Contains(output, "Rating") {
|
||||
t.Fatalf("missing rating")
|
||||
}
|
||||
if !strings.Contains(output, "4.5 (532)") {
|
||||
t.Fatalf("missing rating count")
|
||||
}
|
||||
if !strings.Contains(output, "Open now") {
|
||||
t.Fatalf("missing open now")
|
||||
}
|
||||
@ -43,6 +48,24 @@ func TestRenderSearch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderSearchRatingCountOnly(t *testing.T) {
|
||||
ratingCount := 12
|
||||
response := goplaces.SearchResponse{
|
||||
Results: []goplaces.PlaceSummary{
|
||||
{
|
||||
PlaceID: "abc",
|
||||
Name: "Cafe",
|
||||
UserRatingCount: &ratingCount,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
output := renderSearch(NewColor(false), response)
|
||||
if !strings.Contains(output, "12 ratings") {
|
||||
t.Fatalf("missing rating count-only output: %s", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderSearchEmpty(t *testing.T) {
|
||||
output := renderSearch(NewColor(false), goplaces.SearchResponse{})
|
||||
if !strings.Contains(output, "No results") {
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const nearbyFieldMask = "places.id,places.displayName,places.formattedAddress,places.location,places.rating,places.priceLevel,places.types,places.currentOpeningHours"
|
||||
const nearbyFieldMask = "places.id,places.displayName,places.formattedAddress,places.location,places.rating,places.userRatingCount,places.priceLevel,places.types,places.currentOpeningHours"
|
||||
|
||||
// NearbySearch performs a nearby search around a location restriction.
|
||||
func (c *Client) NearbySearch(ctx context.Context, req NearbySearchRequest) (NearbySearchResponse, error) {
|
||||
|
||||
@ -11,6 +11,7 @@ type placeItem struct {
|
||||
FormattedAddress string `json:"formattedAddress,omitempty"`
|
||||
Location *location `json:"location,omitempty"`
|
||||
Rating *float64 `json:"rating,omitempty"`
|
||||
UserRatingCount *int `json:"userRatingCount,omitempty"`
|
||||
PriceLevel string `json:"priceLevel,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
CurrentOpeningHours *openingHours `json:"currentOpeningHours,omitempty"`
|
||||
|
||||
19
search.go
19
search.go
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const searchFieldMask = "places.id,places.displayName,places.formattedAddress,places.location,places.rating,places.priceLevel,places.types,places.currentOpeningHours,nextPageToken"
|
||||
const searchFieldMask = "places.id,places.displayName,places.formattedAddress,places.location,places.rating,places.userRatingCount,places.priceLevel,places.types,places.currentOpeningHours,nextPageToken"
|
||||
|
||||
// Search performs a text search with optional filters.
|
||||
func (c *Client) Search(ctx context.Context, req SearchRequest) (SearchResponse, error) {
|
||||
@ -100,14 +100,15 @@ func buildSearchBody(req SearchRequest) map[string]any {
|
||||
|
||||
func mapPlaceSummary(place placeItem) PlaceSummary {
|
||||
return PlaceSummary{
|
||||
PlaceID: place.ID,
|
||||
Name: displayName(place.DisplayName),
|
||||
Address: place.FormattedAddress,
|
||||
Location: mapLatLng(place.Location),
|
||||
Rating: place.Rating,
|
||||
PriceLevel: mapPriceLevel(place.PriceLevel),
|
||||
Types: place.Types,
|
||||
OpenNow: openNow(place.CurrentOpeningHours),
|
||||
PlaceID: place.ID,
|
||||
Name: displayName(place.DisplayName),
|
||||
Address: place.FormattedAddress,
|
||||
Location: mapLatLng(place.Location),
|
||||
Rating: place.Rating,
|
||||
UserRatingCount: place.UserRatingCount,
|
||||
PriceLevel: mapPriceLevel(place.PriceLevel),
|
||||
Types: place.Types,
|
||||
OpenNow: openNow(place.CurrentOpeningHours),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
44
types.go
44
types.go
@ -84,31 +84,33 @@ type NearbySearchResponse struct {
|
||||
|
||||
// PlaceSummary is a compact view of a place.
|
||||
type PlaceSummary struct {
|
||||
PlaceID string `json:"place_id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Location *LatLng `json:"location,omitempty"`
|
||||
Rating *float64 `json:"rating,omitempty"`
|
||||
PriceLevel *int `json:"price_level,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
OpenNow *bool `json:"open_now,omitempty"`
|
||||
PlaceID string `json:"place_id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Location *LatLng `json:"location,omitempty"`
|
||||
Rating *float64 `json:"rating,omitempty"`
|
||||
UserRatingCount *int `json:"user_rating_count,omitempty"`
|
||||
PriceLevel *int `json:"price_level,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
OpenNow *bool `json:"open_now,omitempty"`
|
||||
}
|
||||
|
||||
// PlaceDetails is a detailed view of a place.
|
||||
type PlaceDetails struct {
|
||||
PlaceID string `json:"place_id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Location *LatLng `json:"location,omitempty"`
|
||||
Rating *float64 `json:"rating,omitempty"`
|
||||
PriceLevel *int `json:"price_level,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Website string `json:"website,omitempty"`
|
||||
Hours []string `json:"hours,omitempty"`
|
||||
OpenNow *bool `json:"open_now,omitempty"`
|
||||
Reviews []Review `json:"reviews,omitempty"`
|
||||
Photos []Photo `json:"photos,omitempty"`
|
||||
PlaceID string `json:"place_id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Location *LatLng `json:"location,omitempty"`
|
||||
Rating *float64 `json:"rating,omitempty"`
|
||||
UserRatingCount *int `json:"user_rating_count,omitempty"`
|
||||
PriceLevel *int `json:"price_level,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Website string `json:"website,omitempty"`
|
||||
Hours []string `json:"hours,omitempty"`
|
||||
OpenNow *bool `json:"open_now,omitempty"`
|
||||
Reviews []Review `json:"reviews,omitempty"`
|
||||
Photos []Photo `json:"photos,omitempty"`
|
||||
}
|
||||
|
||||
// LocationResolveRequest resolves a text location into place candidates.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user