Add centroid information when geocoding
I would use the boundary rect, but I'm getting a 500-level error from stadia maps
This commit is contained in:
parent
8feabbc489
commit
2bb4a134b2
10 changed files with 272 additions and 56 deletions
|
|
@ -258,6 +258,24 @@ var Organizations = Table[
|
||||||
Generated: true,
|
Generated: true,
|
||||||
AutoIncr: false,
|
AutoIncr: false,
|
||||||
},
|
},
|
||||||
|
ServiceAreaCentroidX: column{
|
||||||
|
Name: "service_area_centroid_x",
|
||||||
|
DBType: "double precision",
|
||||||
|
Default: "GENERATED",
|
||||||
|
Comment: "",
|
||||||
|
Nullable: true,
|
||||||
|
Generated: true,
|
||||||
|
AutoIncr: false,
|
||||||
|
},
|
||||||
|
ServiceAreaCentroidY: column{
|
||||||
|
Name: "service_area_centroid_y",
|
||||||
|
DBType: "double precision",
|
||||||
|
Default: "GENERATED",
|
||||||
|
Comment: "",
|
||||||
|
Nullable: true,
|
||||||
|
Generated: true,
|
||||||
|
AutoIncr: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Indexes: organizationIndexes{
|
Indexes: organizationIndexes{
|
||||||
OrganizationPkey: index{
|
OrganizationPkey: index{
|
||||||
|
|
@ -372,11 +390,13 @@ type organizationColumns struct {
|
||||||
ServiceAreaXmax column
|
ServiceAreaXmax column
|
||||||
ServiceAreaYmax column
|
ServiceAreaYmax column
|
||||||
ServiceAreaCentroidGeojson column
|
ServiceAreaCentroidGeojson column
|
||||||
|
ServiceAreaCentroidX column
|
||||||
|
ServiceAreaCentroidY column
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c organizationColumns) AsSlice() []column {
|
func (c organizationColumns) AsSlice() []column {
|
||||||
return []column{
|
return []column{
|
||||||
c.ID, c.Name, c.ArcgisID, c.ArcgisName, c.FieldseekerURL, c.ImportDistrictGid, c.Website, c.LogoUUID, c.Slug, c.GeneralManagerName, c.MailingAddressCity, c.MailingAddressPostalCode, c.MailingAddressStreet, c.OfficeAddressCity, c.OfficeAddressPostalCode, c.OfficeAddressStreet, c.ServiceAreaGeometry, c.ServiceAreaSquareMeters, c.ServiceAreaCentroid, c.ServiceAreaExtent, c.OfficeFax, c.OfficePhone, c.ServiceAreaXmin, c.ServiceAreaYmin, c.ServiceAreaXmax, c.ServiceAreaYmax, c.ServiceAreaCentroidGeojson,
|
c.ID, c.Name, c.ArcgisID, c.ArcgisName, c.FieldseekerURL, c.ImportDistrictGid, c.Website, c.LogoUUID, c.Slug, c.GeneralManagerName, c.MailingAddressCity, c.MailingAddressPostalCode, c.MailingAddressStreet, c.OfficeAddressCity, c.OfficeAddressPostalCode, c.OfficeAddressStreet, c.ServiceAreaGeometry, c.ServiceAreaSquareMeters, c.ServiceAreaCentroid, c.ServiceAreaExtent, c.OfficeFax, c.OfficePhone, c.ServiceAreaXmin, c.ServiceAreaYmin, c.ServiceAreaXmax, c.ServiceAreaYmax, c.ServiceAreaCentroidGeojson, c.ServiceAreaCentroidX, c.ServiceAreaCentroidY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2929,6 +2929,8 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization
|
||||||
o.ServiceAreaXmax = func() null.Val[float64] { return m.ServiceAreaXmax }
|
o.ServiceAreaXmax = func() null.Val[float64] { return m.ServiceAreaXmax }
|
||||||
o.ServiceAreaYmax = func() null.Val[float64] { return m.ServiceAreaYmax }
|
o.ServiceAreaYmax = func() null.Val[float64] { return m.ServiceAreaYmax }
|
||||||
o.ServiceAreaCentroidGeojson = func() null.Val[string] { return m.ServiceAreaCentroidGeojson }
|
o.ServiceAreaCentroidGeojson = func() null.Val[string] { return m.ServiceAreaCentroidGeojson }
|
||||||
|
o.ServiceAreaCentroidX = func() null.Val[float64] { return m.ServiceAreaCentroidX }
|
||||||
|
o.ServiceAreaCentroidY = func() null.Val[float64] { return m.ServiceAreaCentroidY }
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if len(m.R.EmailContacts) > 0 {
|
if len(m.R.EmailContacts) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ type OrganizationTemplate struct {
|
||||||
ServiceAreaXmax func() null.Val[float64]
|
ServiceAreaXmax func() null.Val[float64]
|
||||||
ServiceAreaYmax func() null.Val[float64]
|
ServiceAreaYmax func() null.Val[float64]
|
||||||
ServiceAreaCentroidGeojson func() null.Val[string]
|
ServiceAreaCentroidGeojson func() null.Val[string]
|
||||||
|
ServiceAreaCentroidX func() null.Val[float64]
|
||||||
|
ServiceAreaCentroidY func() null.Val[float64]
|
||||||
|
|
||||||
r organizationR
|
r organizationR
|
||||||
f *Factory
|
f *Factory
|
||||||
|
|
@ -971,6 +973,12 @@ func (o OrganizationTemplate) Build() *models.Organization {
|
||||||
if o.ServiceAreaCentroidGeojson != nil {
|
if o.ServiceAreaCentroidGeojson != nil {
|
||||||
m.ServiceAreaCentroidGeojson = o.ServiceAreaCentroidGeojson()
|
m.ServiceAreaCentroidGeojson = o.ServiceAreaCentroidGeojson()
|
||||||
}
|
}
|
||||||
|
if o.ServiceAreaCentroidX != nil {
|
||||||
|
m.ServiceAreaCentroidX = o.ServiceAreaCentroidX()
|
||||||
|
}
|
||||||
|
if o.ServiceAreaCentroidY != nil {
|
||||||
|
m.ServiceAreaCentroidY = o.ServiceAreaCentroidY()
|
||||||
|
}
|
||||||
|
|
||||||
o.setModelRels(m)
|
o.setModelRels(m)
|
||||||
|
|
||||||
|
|
@ -1902,6 +1910,8 @@ func (m organizationMods) RandomizeAllColumns(f *faker.Faker) OrganizationMod {
|
||||||
OrganizationMods.RandomServiceAreaXmax(f),
|
OrganizationMods.RandomServiceAreaXmax(f),
|
||||||
OrganizationMods.RandomServiceAreaYmax(f),
|
OrganizationMods.RandomServiceAreaYmax(f),
|
||||||
OrganizationMods.RandomServiceAreaCentroidGeojson(f),
|
OrganizationMods.RandomServiceAreaCentroidGeojson(f),
|
||||||
|
OrganizationMods.RandomServiceAreaCentroidX(f),
|
||||||
|
OrganizationMods.RandomServiceAreaCentroidY(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3292,6 +3302,112 @@ func (m organizationMods) RandomServiceAreaCentroidGeojsonNotNull(f *faker.Faker
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the model columns to this value
|
||||||
|
func (m organizationMods) ServiceAreaCentroidX(val null.Val[float64]) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidX = func() null.Val[float64] { return val }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Column from the function
|
||||||
|
func (m organizationMods) ServiceAreaCentroidXFunc(f func() null.Val[float64]) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidX = f
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any values for the column
|
||||||
|
func (m organizationMods) UnsetServiceAreaCentroidX() OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidX = nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a random value for the column using the given faker
|
||||||
|
// if faker is nil, a default faker is used
|
||||||
|
// The generated value is sometimes null
|
||||||
|
func (m organizationMods) RandomServiceAreaCentroidX(f *faker.Faker) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidX = func() null.Val[float64] {
|
||||||
|
if f == nil {
|
||||||
|
f = &defaultFaker
|
||||||
|
}
|
||||||
|
|
||||||
|
val := random_float64(f)
|
||||||
|
return null.From(val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a random value for the column using the given faker
|
||||||
|
// if faker is nil, a default faker is used
|
||||||
|
// The generated value is never null
|
||||||
|
func (m organizationMods) RandomServiceAreaCentroidXNotNull(f *faker.Faker) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidX = func() null.Val[float64] {
|
||||||
|
if f == nil {
|
||||||
|
f = &defaultFaker
|
||||||
|
}
|
||||||
|
|
||||||
|
val := random_float64(f)
|
||||||
|
return null.From(val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the model columns to this value
|
||||||
|
func (m organizationMods) ServiceAreaCentroidY(val null.Val[float64]) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidY = func() null.Val[float64] { return val }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Column from the function
|
||||||
|
func (m organizationMods) ServiceAreaCentroidYFunc(f func() null.Val[float64]) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidY = f
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any values for the column
|
||||||
|
func (m organizationMods) UnsetServiceAreaCentroidY() OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidY = nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a random value for the column using the given faker
|
||||||
|
// if faker is nil, a default faker is used
|
||||||
|
// The generated value is sometimes null
|
||||||
|
func (m organizationMods) RandomServiceAreaCentroidY(f *faker.Faker) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidY = func() null.Val[float64] {
|
||||||
|
if f == nil {
|
||||||
|
f = &defaultFaker
|
||||||
|
}
|
||||||
|
|
||||||
|
val := random_float64(f)
|
||||||
|
return null.From(val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a random value for the column using the given faker
|
||||||
|
// if faker is nil, a default faker is used
|
||||||
|
// The generated value is never null
|
||||||
|
func (m organizationMods) RandomServiceAreaCentroidYNotNull(f *faker.Faker) OrganizationMod {
|
||||||
|
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
|
||||||
|
o.ServiceAreaCentroidY = func() null.Val[float64] {
|
||||||
|
if f == nil {
|
||||||
|
f = &defaultFaker
|
||||||
|
}
|
||||||
|
|
||||||
|
val := random_float64(f)
|
||||||
|
return null.From(val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (m organizationMods) WithParentsCascading() OrganizationMod {
|
func (m organizationMods) WithParentsCascading() OrganizationMod {
|
||||||
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
|
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
|
||||||
if isDone, _ := organizationWithParentsCascadingCtx.Value(ctx); isDone {
|
if isDone, _ := organizationWithParentsCascadingCtx.Value(ctx); isDone {
|
||||||
|
|
|
||||||
3
db/migrations/00067_org_centroid_coords.sql
Normal file
3
db/migrations/00067_org_centroid_coords.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- +goose Up
|
||||||
|
ALTER TABLE organization ADD COLUMN service_area_centroid_x DOUBLE PRECISION GENERATED ALWAYS AS (ST_X(ST_Centroid(service_area_geometry))) STORED;
|
||||||
|
ALTER TABLE organization ADD COLUMN service_area_centroid_y DOUBLE PRECISION GENERATED ALWAYS AS (ST_Y(ST_Centroid(service_area_geometry))) STORED;
|
||||||
|
|
@ -56,6 +56,8 @@ type Organization struct {
|
||||||
ServiceAreaXmax null.Val[float64] `db:"service_area_xmax,generated" `
|
ServiceAreaXmax null.Val[float64] `db:"service_area_xmax,generated" `
|
||||||
ServiceAreaYmax null.Val[float64] `db:"service_area_ymax,generated" `
|
ServiceAreaYmax null.Val[float64] `db:"service_area_ymax,generated" `
|
||||||
ServiceAreaCentroidGeojson null.Val[string] `db:"service_area_centroid_geojson,generated" `
|
ServiceAreaCentroidGeojson null.Val[string] `db:"service_area_centroid_geojson,generated" `
|
||||||
|
ServiceAreaCentroidX null.Val[float64] `db:"service_area_centroid_x,generated" `
|
||||||
|
ServiceAreaCentroidY null.Val[float64] `db:"service_area_centroid_y,generated" `
|
||||||
|
|
||||||
R organizationR `db:"-" `
|
R organizationR `db:"-" `
|
||||||
|
|
||||||
|
|
@ -118,7 +120,7 @@ type organizationR struct {
|
||||||
func buildOrganizationColumns(alias string) organizationColumns {
|
func buildOrganizationColumns(alias string) organizationColumns {
|
||||||
return organizationColumns{
|
return organizationColumns{
|
||||||
ColumnsExpr: expr.NewColumnsExpr(
|
ColumnsExpr: expr.NewColumnsExpr(
|
||||||
"id", "name", "arcgis_id", "arcgis_name", "fieldseeker_url", "import_district_gid", "website", "logo_uuid", "slug", "general_manager_name", "mailing_address_city", "mailing_address_postal_code", "mailing_address_street", "office_address_city", "office_address_postal_code", "office_address_street", "service_area_geometry", "service_area_square_meters", "service_area_centroid", "service_area_extent", "office_fax", "office_phone", "service_area_xmin", "service_area_ymin", "service_area_xmax", "service_area_ymax", "service_area_centroid_geojson",
|
"id", "name", "arcgis_id", "arcgis_name", "fieldseeker_url", "import_district_gid", "website", "logo_uuid", "slug", "general_manager_name", "mailing_address_city", "mailing_address_postal_code", "mailing_address_street", "office_address_city", "office_address_postal_code", "office_address_street", "service_area_geometry", "service_area_square_meters", "service_area_centroid", "service_area_extent", "office_fax", "office_phone", "service_area_xmin", "service_area_ymin", "service_area_xmax", "service_area_ymax", "service_area_centroid_geojson", "service_area_centroid_x", "service_area_centroid_y",
|
||||||
).WithParent("organization"),
|
).WithParent("organization"),
|
||||||
tableAlias: alias,
|
tableAlias: alias,
|
||||||
ID: psql.Quote(alias, "id"),
|
ID: psql.Quote(alias, "id"),
|
||||||
|
|
@ -148,6 +150,8 @@ func buildOrganizationColumns(alias string) organizationColumns {
|
||||||
ServiceAreaXmax: psql.Quote(alias, "service_area_xmax"),
|
ServiceAreaXmax: psql.Quote(alias, "service_area_xmax"),
|
||||||
ServiceAreaYmax: psql.Quote(alias, "service_area_ymax"),
|
ServiceAreaYmax: psql.Quote(alias, "service_area_ymax"),
|
||||||
ServiceAreaCentroidGeojson: psql.Quote(alias, "service_area_centroid_geojson"),
|
ServiceAreaCentroidGeojson: psql.Quote(alias, "service_area_centroid_geojson"),
|
||||||
|
ServiceAreaCentroidX: psql.Quote(alias, "service_area_centroid_x"),
|
||||||
|
ServiceAreaCentroidY: psql.Quote(alias, "service_area_centroid_y"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,6 +185,8 @@ type organizationColumns struct {
|
||||||
ServiceAreaXmax psql.Expression
|
ServiceAreaXmax psql.Expression
|
||||||
ServiceAreaYmax psql.Expression
|
ServiceAreaYmax psql.Expression
|
||||||
ServiceAreaCentroidGeojson psql.Expression
|
ServiceAreaCentroidGeojson psql.Expression
|
||||||
|
ServiceAreaCentroidX psql.Expression
|
||||||
|
ServiceAreaCentroidY psql.Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c organizationColumns) Alias() string {
|
func (c organizationColumns) Alias() string {
|
||||||
|
|
@ -4449,6 +4455,8 @@ type organizationWhere[Q psql.Filterable] struct {
|
||||||
ServiceAreaXmax psql.WhereNullMod[Q, float64]
|
ServiceAreaXmax psql.WhereNullMod[Q, float64]
|
||||||
ServiceAreaYmax psql.WhereNullMod[Q, float64]
|
ServiceAreaYmax psql.WhereNullMod[Q, float64]
|
||||||
ServiceAreaCentroidGeojson psql.WhereNullMod[Q, string]
|
ServiceAreaCentroidGeojson psql.WhereNullMod[Q, string]
|
||||||
|
ServiceAreaCentroidX psql.WhereNullMod[Q, float64]
|
||||||
|
ServiceAreaCentroidY psql.WhereNullMod[Q, float64]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (organizationWhere[Q]) AliasedAs(alias string) organizationWhere[Q] {
|
func (organizationWhere[Q]) AliasedAs(alias string) organizationWhere[Q] {
|
||||||
|
|
@ -4484,6 +4492,8 @@ func buildOrganizationWhere[Q psql.Filterable](cols organizationColumns) organiz
|
||||||
ServiceAreaXmax: psql.WhereNull[Q, float64](cols.ServiceAreaXmax),
|
ServiceAreaXmax: psql.WhereNull[Q, float64](cols.ServiceAreaXmax),
|
||||||
ServiceAreaYmax: psql.WhereNull[Q, float64](cols.ServiceAreaYmax),
|
ServiceAreaYmax: psql.WhereNull[Q, float64](cols.ServiceAreaYmax),
|
||||||
ServiceAreaCentroidGeojson: psql.WhereNull[Q, string](cols.ServiceAreaCentroidGeojson),
|
ServiceAreaCentroidGeojson: psql.WhereNull[Q, string](cols.ServiceAreaCentroidGeojson),
|
||||||
|
ServiceAreaCentroidX: psql.WhereNull[Q, float64](cols.ServiceAreaCentroidX),
|
||||||
|
ServiceAreaCentroidY: psql.WhereNull[Q, float64](cols.ServiceAreaCentroidY),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,7 @@ func errorMissingHeader(ctx context.Context, txn bob.Tx, c *models.FileuploadCSV
|
||||||
return addError(ctx, txn, c, 0, 0, msg)
|
return addError(ctx, txn, c, 0, 0, msg)
|
||||||
}
|
}
|
||||||
func maybeAddServiceArea(req *stadia.StructuredGeocodeRequest, org *models.Organization) {
|
func maybeAddServiceArea(req *stadia.StructuredGeocodeRequest, org *models.Organization) {
|
||||||
|
/*
|
||||||
if org.ServiceAreaXmax.IsNull() ||
|
if org.ServiceAreaXmax.IsNull() ||
|
||||||
org.ServiceAreaYmax.IsNull() ||
|
org.ServiceAreaYmax.IsNull() ||
|
||||||
org.ServiceAreaXmin.IsNull() ||
|
org.ServiceAreaXmin.IsNull() ||
|
||||||
|
|
@ -393,6 +394,14 @@ func maybeAddServiceArea(req *stadia.StructuredGeocodeRequest, org *models.Organ
|
||||||
req.BoundaryRectMaxLat = &ymax
|
req.BoundaryRectMaxLat = &ymax
|
||||||
req.BoundaryRectMinLon = &xmin
|
req.BoundaryRectMinLon = &xmin
|
||||||
req.BoundaryRectMinLat = &ymin
|
req.BoundaryRectMinLat = &ymin
|
||||||
|
*/
|
||||||
|
if org.ServiceAreaCentroidX.IsNull() || org.ServiceAreaCentroidY.IsNull() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
centroid_x := org.ServiceAreaCentroidX.MustGet()
|
||||||
|
centroid_y := org.ServiceAreaCentroidY.MustGet()
|
||||||
|
req.FocusPointLat = ¢roid_y
|
||||||
|
req.FocusPointLng = ¢roid_x
|
||||||
}
|
}
|
||||||
func parseHeaders(row []string) ([]headerPoolEnum, []string) {
|
func parseHeaders(row []string) ([]headerPoolEnum, []string) {
|
||||||
result_enums := make([]headerPoolEnum, 0)
|
result_enums := make([]headerPoolEnum, 0)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ func main() {
|
||||||
boundaryRectMinLat := flag.Float64("boundary-rect-min-lat", 0, "The min 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")
|
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")
|
boundaryRectMinLon := flag.Float64("boundary-rect-min-lng", 0, "The min lon of the boundary")
|
||||||
|
city := flag.String("city", "", "City address to geocode")
|
||||||
postalCode := flag.String("postal-code", "", "Postal code")
|
postalCode := flag.String("postal-code", "", "Postal code")
|
||||||
focusLat := flag.Float64("focus-lat", 0, "The latitude of the focus point")
|
focusLat := flag.Float64("focus-lat", 0, "The latitude of the focus point")
|
||||||
focusLng := flag.Float64("focus-lng", 0, "The longitude of the focus point")
|
focusLng := flag.Float64("focus-lng", 0, "The longitude of the focus point")
|
||||||
|
|
@ -35,23 +36,23 @@ func main() {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if focusLat != nil && focusLng == nil {
|
if *focusLat != 0 && *focusLng == 0 {
|
||||||
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lat")
|
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lat")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if focusLat == nil && focusLng != nil {
|
if *focusLat == 0 && *focusLng != 0 {
|
||||||
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lng")
|
log.Println("Error: you must specify both focus-lat and focus-lng together, not just focus-lng")
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if (boundaryRectMaxLat != nil ||
|
if (*boundaryRectMaxLat != 0 ||
|
||||||
boundaryRectMinLat != nil ||
|
*boundaryRectMinLat != 0 ||
|
||||||
boundaryRectMaxLon != nil ||
|
*boundaryRectMaxLon != 0 ||
|
||||||
boundaryRectMinLon != nil) && (boundaryRectMaxLat == nil ||
|
*boundaryRectMinLon != 0) && (*boundaryRectMaxLat == 0 ||
|
||||||
boundaryRectMinLat == nil ||
|
*boundaryRectMinLat == 0 ||
|
||||||
boundaryRectMaxLon == nil ||
|
*boundaryRectMaxLon == 0 ||
|
||||||
boundaryRectMinLon == nil) {
|
*boundaryRectMinLon == 0) {
|
||||||
log.Println("If you specify one of boundary-rect you need to specify them all")
|
log.Println("If you specify one of boundary-rect you need to specify them all")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
@ -68,16 +69,19 @@ func main() {
|
||||||
Address: address,
|
Address: address,
|
||||||
PostalCode: postalCode,
|
PostalCode: postalCode,
|
||||||
}
|
}
|
||||||
if focusLat != nil && focusLng != nil {
|
if *focusLat != 0 && *focusLng != 0 {
|
||||||
req.FocusPointLat = focusLat
|
req.FocusPointLat = focusLat
|
||||||
req.FocusPointLng = focusLng
|
req.FocusPointLng = focusLng
|
||||||
}
|
}
|
||||||
if boundaryRectMaxLat != nil {
|
if *boundaryRectMaxLat != 0 {
|
||||||
req.BoundaryRectMaxLat = boundaryRectMaxLat
|
req.BoundaryRectMaxLat = boundaryRectMaxLat
|
||||||
req.BoundaryRectMinLat = boundaryRectMinLat
|
req.BoundaryRectMinLat = boundaryRectMinLat
|
||||||
req.BoundaryRectMaxLon = boundaryRectMaxLon
|
req.BoundaryRectMaxLon = boundaryRectMaxLon
|
||||||
req.BoundaryRectMinLon = boundaryRectMinLon
|
req.BoundaryRectMinLon = boundaryRectMinLon
|
||||||
}
|
}
|
||||||
|
if *city != "" {
|
||||||
|
req.Locality = city
|
||||||
|
}
|
||||||
resp, err := client.StructuredGeocode(ctx, req)
|
resp, err := client.StructuredGeocode(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("err: %v\n", err)
|
log.Printf("err: %v\n", err)
|
||||||
|
|
@ -86,7 +90,7 @@ func main() {
|
||||||
log.Printf("type: %s, features: %d\n", resp.Type, len(resp.Features))
|
log.Printf("type: %s, features: %d\n", resp.Type, len(resp.Features))
|
||||||
for i, feature := range resp.Features {
|
for i, feature := range resp.Features {
|
||||||
log.Printf("feature %d: type %s\n", i, feature.Type)
|
log.Printf("feature %d: type %s\n", i, feature.Type)
|
||||||
log.Printf("\tgeometry %s\n", feature.Geometry.Type)
|
log.Printf("\tgeometry %s (%f %f)\n", feature.Geometry.Type, feature.Geometry.Coordinates[0], feature.Geometry.Coordinates[1])
|
||||||
log.Printf("\tproperties %s\n", feature.Properties.Layer)
|
log.Printf("\tproperties %s\n", feature.Properties.Layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
80
stadia/error.go
Normal file
80
stadia/error.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package stadia
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"resty.dev/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unfortunately, Stadia Maps is inconsistent in how it handles errors.
|
||||||
|
// We therefore have to have a function that handles all the different JSON
|
||||||
|
// error variations.
|
||||||
|
func parseError(resp *resty.Response) error {
|
||||||
|
content, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("reading all body: %w", err)
|
||||||
|
}
|
||||||
|
var server_error serverError
|
||||||
|
err = json.Unmarshal(content, &server_error)
|
||||||
|
if err == nil {
|
||||||
|
return newAPIError(resp.StatusCode(), server_error.Error.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we've exhausted all of our options, so just pass the JSON through
|
||||||
|
return newAPIError(resp.StatusCode(), string(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiError struct {
|
||||||
|
Message string
|
||||||
|
Status int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAPIError(status int, msg string) apiError {
|
||||||
|
return apiError{
|
||||||
|
Message: msg,
|
||||||
|
Status: status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (e apiError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
ErrorMessage string `json:"error"`
|
||||||
|
Errors []string `json:"errors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return e.ErrorMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Got this when I managed to bork the server
|
||||||
|
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"reason": "Internal Server Error"
|
||||||
|
},
|
||||||
|
"status": 500
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
type errorWithReason struct {
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
type serverError struct {
|
||||||
|
Error errorWithReason `json:"error"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if len(result.Geocode.Errors) > 0 {
|
||||||
|
joined := strings.Join(result.Geocode.Errors, ", ")
|
||||||
|
return nil, fmt.Errorf("structured geocoding failure: %d '%s'", resp.StatusCode(), joined)
|
||||||
|
} else if result.Geocode.Error != "" {
|
||||||
|
return nil, fmt.Errorf("structured geocoding failure: %d '%s'", resp.StatusCode(), result.Geocode.Error)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("structured geocoding failure: %d", resp.StatusCode())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
@ -1,18 +1,9 @@
|
||||||
package stadia
|
package stadia
|
||||||
|
|
||||||
type Error struct {
|
|
||||||
ErrorMessage string `json:"error"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return e.ErrorMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// GeocodeResponse represents the top-level response from the geocoding API
|
// GeocodeResponse represents the top-level response from the geocoding API
|
||||||
type GeocodeResponse struct {
|
type GeocodeResponse struct {
|
||||||
BBox []float64 `json:"bbox"` // [W, S, E, N]
|
BBox []float64 `json:"bbox"` // [W, S, E, N]
|
||||||
ErrorMessage string `json:"error"`
|
ErrorMessage string `json:"error,omitempty"`
|
||||||
Features []GeocodeFeature `json:"features"`
|
Features []GeocodeFeature `json:"features"`
|
||||||
Geocode GeocodeMeta `json:"geocoding"`
|
Geocode GeocodeMeta `json:"geocoding"`
|
||||||
Type string `json:"type"` // Should be "FeatureCollection"
|
Type string `json:"type"` // Should be "FeatureCollection"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package stadia
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
)
|
)
|
||||||
|
|
@ -58,7 +57,6 @@ func (s *StadiaMaps) StructuredGeocode(ctx context.Context, req StructuredGeocod
|
||||||
resp, err := s.client.R().
|
resp, err := s.client.R().
|
||||||
SetQueryParamsFromValues(query).
|
SetQueryParamsFromValues(query).
|
||||||
SetContext(ctx).
|
SetContext(ctx).
|
||||||
SetError(&result).
|
|
||||||
SetResult(&result).
|
SetResult(&result).
|
||||||
SetPathParam("urlBase", s.urlBase).
|
SetPathParam("urlBase", s.urlBase).
|
||||||
SetQueryParam("api_key", s.APIKey).
|
SetQueryParam("api_key", s.APIKey).
|
||||||
|
|
@ -68,24 +66,7 @@ func (s *StadiaMaps) StructuredGeocode(ctx context.Context, req StructuredGeocod
|
||||||
}
|
}
|
||||||
|
|
||||||
if !resp.IsSuccess() {
|
if !resp.IsSuccess() {
|
||||||
/*
|
return nil, parseError(resp)
|
||||||
if api_error.Error() != "" {
|
|
||||||
return nil, &api_error
|
|
||||||
}
|
|
||||||
content, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("read all failure: %w", err)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
fmt.Printf("geocoding error: %s\n", result.Geocode.Error)
|
|
||||||
if len(result.Geocode.Errors) > 0 {
|
|
||||||
joined := strings.Join(result.Geocode.Errors, ", ")
|
|
||||||
return nil, fmt.Errorf("structured geocoding failure: %d '%s'", resp.StatusCode(), joined)
|
|
||||||
} else if result.Geocode.Error != "" {
|
|
||||||
return nil, fmt.Errorf("structured geocoding failure: %d '%s'", resp.StatusCode(), result.Geocode.Error)
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("structured geocoding failure: %d", resp.StatusCode())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue