Add proxied autocomplete for Stadia
This allows me to make the format consistent and to cache the intermediate results, which is useful for speed and testing
This commit is contained in:
parent
b6cfbee102
commit
2d5dca3fb5
11 changed files with 275 additions and 11 deletions
99
stadia/cmd/geocode-autocomplete/main.go
Normal file
99
stadia/cmd/geocode-autocomplete/main.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/stadia"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Define command-line flags
|
||||
query := flag.String("query", "", "Street address query to autocomplete")
|
||||
boundaryRectMaxLat := flag.Float64("boundary-rect-max-lat", 0, "The max lat of the boundary")
|
||||
boundaryRectMinLat := flag.Float64("boundary-rect-min-lat", 0, "The min lat of the boundary")
|
||||
boundaryRectMaxLon := flag.Float64("boundary-rect-max-lng", 0, "The max lon of the boundary")
|
||||
boundaryRectMinLon := flag.Float64("boundary-rect-min-lng", 0, "The min lon of the boundary")
|
||||
focusLat := flag.Float64("focus-lat", 0, "The latitude of the focus point")
|
||||
focusLng := flag.Float64("focus-lng", 0, "The longitude of the focus point")
|
||||
|
||||
// Parse the flags
|
||||
flag.Parse()
|
||||
|
||||
// Validate required arguments
|
||||
if *query == "" {
|
||||
log.Println("Error: -query is required")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *focusLat != 0 && *focusLng == 0 {
|
||||
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lat")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if *focusLat == 0 && *focusLng != 0 {
|
||||
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lng")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if (*boundaryRectMaxLat != 0 ||
|
||||
*boundaryRectMinLat != 0 ||
|
||||
*boundaryRectMaxLon != 0 ||
|
||||
*boundaryRectMinLon != 0) && (*boundaryRectMaxLat == 0 ||
|
||||
*boundaryRectMinLat == 0 ||
|
||||
*boundaryRectMaxLon == 0 ||
|
||||
*boundaryRectMinLon == 0) {
|
||||
log.Println("If you specify one of boundary-rect you need to specify them all")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
key := os.Getenv("STADIA_MAPS_API_KEY")
|
||||
if key == "" {
|
||||
log.Println("STADIA_MAPS_API_KEY is empty")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
client := stadia.NewStadiaMaps(key)
|
||||
ctx := context.Background()
|
||||
req := stadia.RequestGeocodeAutocomplete{
|
||||
Text: *query,
|
||||
}
|
||||
if *focusLat != 0 && *focusLng != 0 {
|
||||
req.FocusPointLat = focusLat
|
||||
req.FocusPointLng = focusLng
|
||||
}
|
||||
if *boundaryRectMaxLat != 0 {
|
||||
req.BoundaryRectMaxLat = boundaryRectMaxLat
|
||||
req.BoundaryRectMinLat = boundaryRectMinLat
|
||||
req.BoundaryRectMaxLon = boundaryRectMaxLon
|
||||
req.BoundaryRectMinLon = boundaryRectMinLon
|
||||
}
|
||||
resp, err := client.GeocodeAutocomplete(ctx, req)
|
||||
if err != nil {
|
||||
log.Printf("err: %v\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
log.Printf("type: %s, features: %d\n", resp.Type, len(resp.Features))
|
||||
for i, feature := range resp.Features {
|
||||
log.Printf("feature %d: type %s\n", i, feature.Type)
|
||||
if feature.Geometry == nil {
|
||||
log.Printf("\tno geometry")
|
||||
} else {
|
||||
log.Printf("\tgeometry %s\n", feature.Geometry.Type) //, feature.Geometry.Coordinates[0], feature.Geometry.Coordinates[1])
|
||||
}
|
||||
log.Printf("\tproperties %s\n", feature.Properties.Layer)
|
||||
switch feature.Properties.Layer {
|
||||
case "address":
|
||||
log.Printf("\t\t%s", feature.Properties.Name)
|
||||
if feature.Properties.CoarseLocation != nil {
|
||||
log.Printf("\t\t%s", *feature.Properties.CoarseLocation)
|
||||
}
|
||||
log.Printf("\t\t%s", feature.Properties.Precision)
|
||||
log.Printf("\t\t%s", feature.Properties.Layer)
|
||||
log.Printf("\t\t%s", feature.Properties.GID)
|
||||
}
|
||||
}
|
||||
}
|
||||
72
stadia/geocode_autocomplete.go
Normal file
72
stadia/geocode_autocomplete.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package stadia
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type RequestGeocodeAutocomplete struct {
|
||||
Text string `url:"text" json:"text"`
|
||||
|
||||
// Boundary circle parameters
|
||||
BoundaryCircleLat *float64 `url:"boundary.circle.lat,omitempty"`
|
||||
BoundaryCircleLon *float64 `url:"boundary.circle.lon,omitempty"`
|
||||
BoundaryCircleRadius *float64 `url:"boundary.circle.radius,omitempty"`
|
||||
|
||||
BoundaryCountry *string `url:"boundary.country,omitempty"` //comma-delimited ISO 2 or 3 character code
|
||||
BoundaryGID *string `url:"boundary.gid,omitempty"` // The GID of a region to limit the search to
|
||||
|
||||
// Boundary parameters
|
||||
BoundaryRectMaxLat *float64 `url:"boundary.rect.max_lat,omitempty"`
|
||||
BoundaryRectMinLat *float64 `url:"boundary.rect.min_lat,omitempty"`
|
||||
BoundaryRectMaxLon *float64 `url:"boundary.rect.max_lon,omitempty"`
|
||||
BoundaryRectMinLon *float64 `url:"boundary.rect.min_lon,omitempty"`
|
||||
|
||||
// Focus point
|
||||
FocusPointLat *float64 `url:"focus.point.lat,omitempty" json:",omitempty"`
|
||||
FocusPointLng *float64 `url:"focus.point.lon,omitempty" json:",omitempty"`
|
||||
|
||||
// Other parameters
|
||||
Lang *string `url:"lang,omitempty" json:"lang,omitempty"`
|
||||
Layers []string `url:"layers,omitempty,comma" json:"layers,omitempty"`
|
||||
Size *int `url:"size,omitempty" json:"size,omitempty"`
|
||||
Sources []string `url:"sources,omitempty,comma" json:"sources,omitempty"`
|
||||
}
|
||||
|
||||
func (r *RequestGeocodeAutocomplete) SetBoundaryRect(xmin, ymin, xmax, ymax float64) {
|
||||
r.BoundaryRectMaxLat = &ymax
|
||||
r.BoundaryRectMinLat = &ymin
|
||||
r.BoundaryRectMaxLon = &xmax
|
||||
r.BoundaryRectMinLon = &xmin
|
||||
}
|
||||
func (r *RequestGeocodeAutocomplete) SetFocusPoint(x, y float64) {
|
||||
r.FocusPointLat = &y
|
||||
r.FocusPointLng = &x
|
||||
}
|
||||
func (s *StadiaMaps) GeocodeAutocomplete(ctx context.Context, req RequestGeocodeAutocomplete) (*GeocodeResponse, error) {
|
||||
// https://docs.stadiamaps.com/geocoding-search-autocomplete/search/
|
||||
var result GeocodeResponse
|
||||
|
||||
query, err := query.Values(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("structured geocode query: %w", err)
|
||||
}
|
||||
//var api_error Error
|
||||
resp, err := s.client.R().
|
||||
SetQueryParamsFromValues(query).
|
||||
SetContext(ctx).
|
||||
SetResult(&result).
|
||||
SetPathParam("urlBase", s.urlBase).
|
||||
SetQueryParam("api_key", s.APIKey).
|
||||
Get("https://{urlBase}/geocoding/v2/autocomplete")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("autocomplete get: %w", err)
|
||||
}
|
||||
|
||||
if !resp.IsSuccess() {
|
||||
return nil, parseError(resp)
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ type GeocodeMeta struct {
|
|||
// GeocodeFeature represents a GeoJSON feature in the response
|
||||
type GeocodeFeature struct {
|
||||
Type string `json:"type"` // Should be "Feature"
|
||||
Geometry GeocodeGeometry `json:"geometry"`
|
||||
Geometry *GeocodeGeometry `json:"geometry"`
|
||||
Properties GeocodeProperties `json:"properties"`
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +113,7 @@ type GeocodeProperties struct {
|
|||
Addendum map[string]interface{} `json:"addendum,omitempty"`
|
||||
AddressComponents AddressComponents `json:"address_components,omitempty"`
|
||||
Accuracy string `json:"accuracy"` // 'point'
|
||||
CoarseLocation *string `json:"coarse_location"` // 'Riverton, UT, USA'
|
||||
Confidence float64 `json:"confidence"` // 1
|
||||
Context Context `json:"context,omitempty"` // bunch of stuff
|
||||
Country string `json:"country"` // 'United States'
|
||||
|
|
@ -132,6 +133,7 @@ type GeocodeProperties struct {
|
|||
MatchType string `json:"match_type"` // 'exact'
|
||||
Name string `json:"name"` // '1234 Main St'
|
||||
PostalCode string `json:"postalcode"` // '93618'
|
||||
Precision string `json:"precision"` // 'centroid'
|
||||
Region string `json:"region"` // 'California'
|
||||
RegionA string `json:"region_a"` // 'CA'
|
||||
RegionGID string `json:"region_gid"` // 'whosonfirst:region:85688637'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue