diff --git a/geocoding.go b/geocoding.go index 552c991..f0fe4d8 100644 --- a/geocoding.go +++ b/geocoding.go @@ -6,11 +6,17 @@ type FeatureCollection struct { Features []Feature `json:"features"` } +// PointGeometry is a GeoJSON Point geometry. Coordinates holds [longitude, latitude]. +type PointGeometry struct { + Type string `json:"type"` + Coordinates []float64 `json:"coordinates"` +} + // Feature is a GeoJSON Feature with Mapbox v6 geocoding properties. type Feature struct { Type string `json:"type"` ID string `json:"id"` - Geometry GeoJSONGeometry `json:"geometry"` + Geometry PointGeometry `json:"geometry"` Properties FeatureProperties `json:"properties"` } diff --git a/geocoding_batch_reverse.go b/geocoding_batch_reverse.go index 78c5d7e..ab4d904 100644 --- a/geocoding_batch_reverse.go +++ b/geocoding_batch_reverse.go @@ -13,6 +13,9 @@ import ( type BatchReverseGeocodeRequest struct { // Queries are the coordinates to reverse geocode. Must contain 1–1000 items. Queries []ReverseGeocodeQuery + // Permanent requests Permanent tier geocoding, which permits storing results. + // Defaults to Temporary tier when false. + Permanent bool } // ReverseGeocodeQuery is a single query in a batch reverse geocode request. @@ -28,6 +31,7 @@ type batchGeocodeQuery struct { Types string `json:"types"` Longitude float64 `json:"longitude"` Latitude float64 `json:"latitude"` + Permanent bool `json:"permanent"` } // BatchReverseGeocode performs a batch reverse geocode lookup using Geocoding v6 Batch. @@ -53,6 +57,7 @@ func (c *Client) BatchReverseGeocode(ctx context.Context, req *BatchReverseGeoco Types: "address", Longitude: q.Longitude, Latitude: q.Latitude, + Permanent: req.Permanent, } } diff --git a/geocoding_reverse.go b/geocoding_reverse.go index 6ed5918..e378ac2 100644 --- a/geocoding_reverse.go +++ b/geocoding_reverse.go @@ -16,6 +16,9 @@ type ReverseGeocodeRequest struct { Longitude float64 // Latitude is the coordinate to reverse geocode. Latitude float64 + // Permanent requests Permanent tier geocoding, which permits storing results. + // Defaults to Temporary tier when false. + Permanent bool } // ReverseGeocode performs a single reverse geocode lookup using Geocoding v6. @@ -29,6 +32,9 @@ func (c *Client) ReverseGeocode(ctx context.Context, req *ReverseGeocodeRequest) params := url.Values{} params.Set("longitude", strconv.FormatFloat(req.Longitude, 'f', -1, 64)) params.Set("latitude", strconv.FormatFloat(req.Latitude, 'f', -1, 64)) + if req.Permanent { + params.Set("permanent", "true") + } endpoint := c.baseURL + "/search/geocode/v6/reverse?" + params.Encode() httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) diff --git a/geocoding_reverse_test.go b/geocoding_reverse_test.go index 405ec34..98d4e9a 100644 --- a/geocoding_reverse_test.go +++ b/geocoding_reverse_test.go @@ -121,6 +121,49 @@ func TestReverseGeocode_ContextParsing(t *testing.T) { } } +func TestReverseGeocode_PointGeometry(t *testing.T) { + // Mapbox returns Point geometry with flat [lon, lat] coordinates. + // Regression: GeoJSONGeometry used [][]float64 (LineString), causing decode to fail. + const body = `{ + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "geometry": {"type": "Point", "coordinates": [24.9384, 60.1699]}, + "properties": { + "mapbox_id": "addr.1", + "feature_type": "address", + "full_address": "Mannerheimintie 1, 00100 Helsinki, Finland" + } + }] + }` + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + if _, err := w.Write([]byte(body)); err != nil { + t.Errorf("write response: %v", err) + } + })) + defer srv.Close() + + client := mapbox.NewClient(mapbox.WithAccessToken("t"), mapbox.WithBaseURL(srv.URL)) + result, err := client.ReverseGeocode(context.Background(), &mapbox.ReverseGeocodeRequest{ + Longitude: 24.9384, + Latitude: 60.1699, + }) + if err != nil { + t.Fatalf("ReverseGeocode error: %v", err) + } + if len(result.Features) != 1 { + t.Fatalf("len(Features) = %d, want 1", len(result.Features)) + } + f := result.Features[0] + if f.Geometry.Type != "Point" { + t.Errorf("Geometry.Type = %q, want Point", f.Geometry.Type) + } + if len(f.Geometry.Coordinates) != 2 { + t.Errorf("Geometry.Coordinates len = %d, want 2", len(f.Geometry.Coordinates)) + } +} + func TestReverseGeocode_HTTPError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, `{"message":"Not Authorized - Invalid Token"}`, http.StatusUnauthorized) diff --git a/searchbox.go b/searchbox.go index b52509f..1019b87 100644 --- a/searchbox.go +++ b/searchbox.go @@ -28,7 +28,7 @@ type Suggestion struct { // RetrieveFeature is a GeoJSON Feature returned by /retrieve. type RetrieveFeature struct { Type string `json:"type"` - Geometry GeoJSONGeometry `json:"geometry"` + Geometry PointGeometry `json:"geometry"` Properties RetrieveFeatureProperties `json:"properties"` }