Skip to content

Commit

Permalink
feat! Added Address Descriptors to Geocoding response. Refactored Geo…
Browse files Browse the repository at this point in the history
…coding response to allow fields outside the geocoding result to be exposed through the client.
  • Loading branch information
Tom Clifford committed Feb 14, 2024
1 parent 51148b6 commit d38bb43
Show file tree
Hide file tree
Showing 3 changed files with 460 additions and 168 deletions.
128 changes: 128 additions & 0 deletions addressdescriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* An enum representing the relationship in space between the landmark and the target.
*/
type SpatialRelationship string

Check failure on line 4 in addressdescriptor.go

View workflow job for this annotation

GitHub Actions / build

expected 'package', found 'type'

const (
// This is the default relationship when nothing more specific below
// applies.
NEAR SpatialRelationship = "NEAR"
// The landmark has a spatial geometry and the target is within its
// bounds.
WITHIN SpatialRelationship = "WITHIN"
// The target is directly adjacent to the landmark or landmark's access
// point.
BESIDE SpatialRelationship = "BESIDE"
// The target is directly opposite the landmark on the other side of the
// road.
ACROSS_THE_ROAD SpatialRelationship = "ACROSS_THE_ROAD"
// On the same route as the landmark but not besides or across.
DOWN_THE_ROAD SpatialRelationship = "DOWN_THE_ROAD"
// Not on the same route as the landmark but a single 'turn' away.
AROUND_THE_CORNER SpatialRelationship = "AROUND_THE_CORNER"
// Close to the landmark's structure but further away from its access
// point.
BEHIND SpatialRelationship = "BEHIND"
)

// String method for formatted output
func (sr SpatialRelationship) String() string {
return string(sr)
}

/**
* An enum representing the relationship in space between the area and the target.
*/
type Containment string

const (
/**
* Indicates an unknown containment returned by the server.
*/
CONTAINMENT_UNSPECIFIED Containment = "CONTAINMENT_UNSPECIFIED"
/** The target location is within the area region, close to the center. */
WITHIN Containment = "WITHIN"
/** The target location is within the area region, close to the edge. */
OUTSKIRTS Containment = "OUTSKIRTS"
/** The target location is outside the area region, but close by. */
NEAR Containment = "NEAR"
)

// String method for formatted output
func (c Containment) String() string {
return string(c)
}

/**
* Localized variant of a text in a particular language.
*/
type LocalizedText struct {
// Localized string in the language corresponding to language_code below.
Text string `json:"text"`
// The text's BCP-47 language code, such as "en-US" or "sr-Latn".
//
// For more information, see
// http://www.unicode.org/reports/tr35/#Unicode_locale_identifier.
LanguageCode string `json:"language_code"`
}

// String method for formatted output
func (lt LocalizedText) String() string {
return fmt.Sprintf("(text=%s, languageCode=%s)", lt.Text, lt.LanguageCode)
}

// Landmarks that are useful at describing a location.
type Landmark struct {
// The Place ID of the underlying establishment serving as the landmark.
// Can be used to resolve more information about the landmark through Place
// Details or Place Id Lookup.
PlaceID string `json:"place_id"`
// The best name for the landmark.
DisplayName LocalizedText `json:"display_name"`
// One or more values indicating the type of the returned result. Please see <a
// href="https://developers.google.com/maps/documentation/places/web-service/supported_types">Types
// </a> for more detail.
Types []string `json:"types"`
// Defines the spatial relationship between the target location and the
// landmark.
SpatialRelationship SpatialRelationship `json:"spatial_relationship"`
// The straight line distance between the target location and one of the
// landmark's access points.
StraightLineDistanceMeters float32 `json:"straight_line_distance_meters"`
// The travel distance along the road network between the target
// location's closest point on a road, and the landmark's closest access
// point on a road. This can be unpopulated if the landmark is disconnected
// from the part of the road network the target is closest to OR if the
// target location was not actually considered to be on the road network.
TravelDistanceMeters float32 `json:"travel_distance_meters"`
}

// Precise regions that are useful at describing a location.
type Area struct {
// The Place ID of the underlying area feature. Can be used to
// resolve more information about the area through Place Details or
// Place Id Lookup.
PlaceID string `json:"place_id"`
// The best name for the area.
DisplayName LocalizedText `json:"display_name"`
/**
* An enum representing the relationship in space between the area and the target.
*/
Containment Containment `json:"containment"`
}

/**
* Represents a descriptor of an address.
*
* <p>Please see <a
* href="https://mapsplatform.google.com/demos/address-descriptors/">Address
* Descriptors</a> for more detail.
*/
type AddressDescriptor struct {
// A ranked list of nearby landmarks. The most useful (recognizable and
// nearby) landmarks are ranked first.
Landmarks []Landmark `json:"landmarks"
// A ranked list of containing or adjacent areas. The most useful
// (recognizable and precise) areas are ranked first.
Areas []Area `json:"areas"`
}
32 changes: 23 additions & 9 deletions geocoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var geocodingAPI = &apiConfig{
}

// Geocode makes a Geocoding API request
func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) (GeocodingResponse, error) {
if r.Address == "" && len(r.Components) == 0 && r.LatLng == nil {
return nil, errors.New("maps: address, components and LatLng are all missing")
}
Expand All @@ -43,38 +43,38 @@ func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingR
}

if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
return nil, err
return GeocodingResponse{}, err
}

if err := response.StatusError(); err != nil {
return nil, err
return GeocodingResponse{}, err
}

return response.Results, nil
return GeocodingResponse{response.Results},, nil
}

// ReverseGeocode makes a Reverse Geocoding API request
func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) (GeocodingResponse, error) {
// Since Geocode() does not allow a nil LatLng, whereas it is allowed here
if r.LatLng == nil && r.PlaceID == "" {
return nil, errors.New("maps: LatLng and PlaceID are both missing")
}

var response struct {
Results []GeocodingResult `json:"results"`
AddressDescriptor AddressDescriptor `json:"address_descriptor"`
commonResponse
}

if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
return nil, err
return GeocodingResponse{}, err
}

if err := response.StatusError(); err != nil {
return nil, err
return GeocodingResponse{}, err
}

return response.Results, nil

return GeocodingResponse{response.Results, response.AddressDescriptor}, nil
}

func (r *GeocodingRequest) params() url.Values {
Expand Down Expand Up @@ -119,6 +119,9 @@ func (r *GeocodingRequest) params() url.Values {
if r.Language != "" {
q.Set("language", r.Language)
}
if r.EnableAddressDescriptor == true {
q.Set("enable_address_descriptor", "true")
}

return q
}
Expand Down Expand Up @@ -176,12 +179,23 @@ type GeocodingRequest struct {
// Language is the language in which to return results. Optional.
Language string

// Language is the language in which to return results. Optional.
EnableAddressDescriptor bool

// Custom allows passing through custom parameters to the Geocoding back end.
// Use with caution. For more detail on why this is required, please see
// https://googlegeodevelopers.blogspot.com/2016/11/address-geocoding-in-google-maps-apis.html
Custom url.Values
}

// GeocodingResponse is the response to a Geocoding API request.
type GeocodingResponse struct {
// Results is the Geocoding results
Results []GeocodingResult
// The Address Descriptor for the target in the reverse geocoding requeest
AddressDescriptor AddressDescriptor
}

// GeocodingResult is a single geocoded address
type GeocodingResult struct {
AddressComponents []AddressComponent `json:"address_components"`
Expand Down
Loading

0 comments on commit d38bb43

Please sign in to comment.