From 730f40956f4a2676e5406b2f166d84fc8e00a932 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Fri, 10 Apr 2026 22:32:40 +0000 Subject: [PATCH] Store addresses on every geocode --- db/dberrors/address.bob.go | 9 ++ db/dbinfo/address.bob.go | 42 +++++- db/enums/enums.bob.go | 70 ---------- db/migrations/00129_address_country_text.sql | 8 ++ db/migrations/00130_address_gid_unique.sql | 7 + db/models/address.bob.go | 31 +++-- platform/csv/csv.go | 12 +- platform/geocode/address.go | 125 +++++++++++++++++ platform/geocode/by_gid.go | 6 + platform/geocode/geocode.go | 133 ++----------------- platform/types/address.go | 8 +- resource/compliance.go | 1 - 12 files changed, 223 insertions(+), 229 deletions(-) create mode 100644 db/migrations/00129_address_country_text.sql create mode 100644 db/migrations/00130_address_gid_unique.sql create mode 100644 platform/geocode/address.go diff --git a/db/dberrors/address.bob.go b/db/dberrors/address.bob.go index 70a942a9..41d7f72f 100644 --- a/db/dberrors/address.bob.go +++ b/db/dberrors/address.bob.go @@ -10,8 +10,17 @@ var AddressErrors = &addressErrors{ columns: []string{"id"}, s: "address_pkey", }, + + ErrUniqueAddressGidUnique: &UniqueConstraintError{ + schema: "", + table: "address", + columns: []string{"gid"}, + s: "address_gid_unique", + }, } type addressErrors struct { ErrUniqueAddressPkey *UniqueConstraintError + + ErrUniqueAddressGidUnique *UniqueConstraintError } diff --git a/db/dbinfo/address.bob.go b/db/dbinfo/address.bob.go index 7f3ceadb..effe360e 100644 --- a/db/dbinfo/address.bob.go +++ b/db/dbinfo/address.bob.go @@ -17,7 +17,7 @@ var Addresses = Table[ Columns: addressColumns{ Country: column{ Name: "country", - DBType: "public.countrytype", + DBType: "text", Default: "", Comment: "", Nullable: false, @@ -160,6 +160,23 @@ var Addresses = Table[ Where: "", Include: []string{}, }, + AddressGidUnique: index{ + Type: "btree", + Name: "address_gid_unique", + Columns: []indexColumn{ + { + Name: "gid", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: true, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, IdxAddressGeom: index{ Type: "gist", Name: "idx_address_geom", @@ -184,6 +201,14 @@ var Addresses = Table[ Comment: "", }, + Uniques: addressUniques{ + AddressGidUnique: constraint{ + Name: "address_gid_unique", + Columns: []string{"gid"}, + Comment: "", + }, + }, + Comment: "", } @@ -211,13 +236,14 @@ func (c addressColumns) AsSlice() []column { } type addressIndexes struct { - AddressPkey index - IdxAddressGeom index + AddressPkey index + AddressGidUnique index + IdxAddressGeom index } func (i addressIndexes) AsSlice() []index { return []index{ - i.AddressPkey, i.IdxAddressGeom, + i.AddressPkey, i.AddressGidUnique, i.IdxAddressGeom, } } @@ -227,10 +253,14 @@ func (f addressForeignKeys) AsSlice() []foreignKey { return []foreignKey{} } -type addressUniques struct{} +type addressUniques struct { + AddressGidUnique constraint +} func (u addressUniques) AsSlice() []constraint { - return []constraint{} + return []constraint{ + u.AddressGidUnique, + } } type addressChecks struct{} diff --git a/db/enums/enums.bob.go b/db/enums/enums.bob.go index eb2085a4..c99b91c7 100644 --- a/db/enums/enums.bob.go +++ b/db/enums/enums.bob.go @@ -846,76 +846,6 @@ func (e *CommsTextorigin) Scan(value any) error { return nil } -// Enum values for Countrytype -const ( - CountrytypeUsa Countrytype = "usa" -) - -func AllCountrytype() []Countrytype { - return []Countrytype{ - CountrytypeUsa, - } -} - -type Countrytype string - -func (e Countrytype) String() string { - return string(e) -} - -func (e Countrytype) Valid() bool { - switch e { - case CountrytypeUsa: - return true - default: - return false - } -} - -// useful when testing in other packages -func (e Countrytype) All() []Countrytype { - return AllCountrytype() -} - -func (e Countrytype) MarshalText() ([]byte, error) { - return []byte(e), nil -} - -func (e *Countrytype) UnmarshalText(text []byte) error { - return e.Scan(text) -} - -func (e Countrytype) MarshalBinary() ([]byte, error) { - return []byte(e), nil -} - -func (e *Countrytype) UnmarshalBinary(data []byte) error { - return e.Scan(data) -} - -func (e Countrytype) Value() (driver.Value, error) { - return string(e), nil -} - -func (e *Countrytype) Scan(value any) error { - switch x := value.(type) { - case string: - *e = Countrytype(x) - case []byte: - *e = Countrytype(x) - case nil: - return fmt.Errorf("cannot nil into Countrytype") - default: - return fmt.Errorf("cannot scan type %T: %v", value, value) - } - - if !e.Valid() { - return fmt.Errorf("invalid Countrytype value: %s", *e) - } - - return nil -} - // Enum values for FileuploadCsvtype const ( FileuploadCsvtypePoollist FileuploadCsvtype = "PoolList" diff --git a/db/migrations/00129_address_country_text.sql b/db/migrations/00129_address_country_text.sql new file mode 100644 index 00000000..0da42640 --- /dev/null +++ b/db/migrations/00129_address_country_text.sql @@ -0,0 +1,8 @@ +-- +goose Up +ALTER TABLE address +ALTER COLUMN country +TYPE TEXT +USING country::TEXT; +DROP TYPE CountryType; +-- +goose Down + diff --git a/db/migrations/00130_address_gid_unique.sql b/db/migrations/00130_address_gid_unique.sql new file mode 100644 index 00000000..f38150a3 --- /dev/null +++ b/db/migrations/00130_address_gid_unique.sql @@ -0,0 +1,7 @@ +-- +goose Up +UPDATE address +SET gid = gen_random_uuid() +WHERE gid = ''; +ALTER TABLE address ADD CONSTRAINT address_gid_unique UNIQUE (gid); +-- +goose Down +ALTER TABLE address DROP CONSTRAINT address_gid_unique; diff --git a/db/models/address.bob.go b/db/models/address.bob.go index 82745e1f..5f3e612b 100644 --- a/db/models/address.bob.go +++ b/db/models/address.bob.go @@ -18,7 +18,6 @@ import ( "github.com/Gleipnir-Technology/bob/expr" "github.com/Gleipnir-Technology/bob/orm" "github.com/Gleipnir-Technology/bob/types/pgtypes" - enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" "github.com/aarondl/opt/omitnull" @@ -26,7 +25,7 @@ import ( // Address is an object representing the database table. type Address struct { - Country enums.Countrytype `db:"country" ` + Country string `db:"country" ` Created time.Time `db:"created" ` Location string `db:"location" ` H3cell string `db:"h3cell" ` @@ -118,18 +117,18 @@ func (addressColumns) AliasedAs(alias string) addressColumns { // All values are optional, and do not have to be set // Generated columns are not included type AddressSetter struct { - Country omit.Val[enums.Countrytype] `db:"country" ` - Created omit.Val[time.Time] `db:"created" ` - Location omit.Val[string] `db:"location" ` - H3cell omit.Val[string] `db:"h3cell" ` - ID omit.Val[int32] `db:"id,pk" ` - Locality omit.Val[string] `db:"locality" ` - PostalCode omit.Val[string] `db:"postal_code" ` - Street omit.Val[string] `db:"street" ` - Unit omit.Val[string] `db:"unit" ` - Region omit.Val[string] `db:"region" ` - Number omit.Val[string] `db:"number_" ` - Gid omit.Val[string] `db:"gid" ` + Country omit.Val[string] `db:"country" ` + Created omit.Val[time.Time] `db:"created" ` + Location omit.Val[string] `db:"location" ` + H3cell omit.Val[string] `db:"h3cell" ` + ID omit.Val[int32] `db:"id,pk" ` + Locality omit.Val[string] `db:"locality" ` + PostalCode omit.Val[string] `db:"postal_code" ` + Street omit.Val[string] `db:"street" ` + Unit omit.Val[string] `db:"unit" ` + Region omit.Val[string] `db:"region" ` + Number omit.Val[string] `db:"number_" ` + Gid omit.Val[string] `db:"gid" ` } func (s AddressSetter) SetColumns() []string { @@ -1151,7 +1150,7 @@ func (address0 *Address) AttachSite(ctx context.Context, exec bob.Executor, site } type addressWhere[Q psql.Filterable] struct { - Country psql.WhereMod[Q, enums.Countrytype] + Country psql.WhereMod[Q, string] Created psql.WhereMod[Q, time.Time] Location psql.WhereMod[Q, string] H3cell psql.WhereMod[Q, string] @@ -1173,7 +1172,7 @@ func (addressWhere[Q]) AliasedAs(alias string) addressWhere[Q] { func buildAddressWhere[Q psql.Filterable](cols addressColumns) addressWhere[Q] { return addressWhere[Q]{ - Country: psql.Where[Q, enums.Countrytype](cols.Country), + Country: psql.Where[Q, string](cols.Country), Created: psql.Where[Q, time.Time](cols.Created), Location: psql.Where[Q, string](cols.Location), H3cell: psql.Where[Q, string](cols.H3cell), diff --git a/platform/csv/csv.go b/platform/csv/csv.go index bfc60a76..40f97a60 100644 --- a/platform/csv/csv.go +++ b/platform/csv/csv.go @@ -60,23 +60,23 @@ func JobCommit(ctx context.Context, txn bob.Executor, file_id int32) error { Street: row.AddressStreet, Unit: "", } - address, err := geocode.EnsureAddressWithGeocode(ctx, txn, org, a) + geo, err := geocode.GeocodeStructured(ctx, org, a) if err != nil { //return fmt.Errorf("ensure address: %w", err) - if address == nil { + if geo == nil || geo.Address.ID == nil { log.Warn().Err(err).Msg("ensure address failure") } else { - log.Warn().Err(err).Int32("address.id", address.ID).Msg("ensure address failure") + log.Warn().Err(err).Int32("address.id", *geo.Address.ID).Msg("ensure address failure") } continue } - parcel, err := geocode.GetParcel(ctx, txn, address) + parcel, err := geocode.GetParcel(ctx, txn, geo.Address) if err != nil { return fmt.Errorf("get parcel: %w", err) } var site *models.Site site, err = models.Sites.Query( - models.SelectWhere.Sites.AddressID.EQ(address.ID), + models.SelectWhere.Sites.AddressID.EQ(*geo.Address.ID), ).One(ctx, txn) if err != nil { if err.Error() != "sql: no rows in result set" { @@ -87,7 +87,7 @@ func JobCommit(ctx context.Context, txn bob.Executor, file_id int32) error { parcel_id = &(*parcel).ID } setter := models.SiteSetter{ - AddressID: omit.From(address.ID), + AddressID: omit.From(*geo.Address.ID), Created: omit.From(time.Now()), CreatorID: omit.FromPtr(file.Committer.Ptr()), FileID: omitnull.From(file_id), diff --git a/platform/geocode/address.go b/platform/geocode/address.go new file mode 100644 index 00000000..3bb8cde7 --- /dev/null +++ b/platform/geocode/address.go @@ -0,0 +1,125 @@ +package geocode + +import ( + "context" + "fmt" + "time" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/im" + //bobtypes "github.com/Gleipnir-Technology/bob/types" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/Gleipnir-Technology/nidus-sync/h3utils" + "github.com/Gleipnir-Technology/nidus-sync/platform/types" + "github.com/Gleipnir-Technology/nidus-sync/stadia" + "github.com/rs/zerolog/log" + "github.com/stephenafamo/scan" +) + +// Ensure the provided address exists. If it doesn't add it to the database. +func EnsureAddress(ctx context.Context, txn bob.Executor, a types.Address, l types.Location) (*models.Address, error) { + address, err := models.Addresses.Query( + models.SelectWhere.Addresses.Country.EQ(a.Country), + models.SelectWhere.Addresses.Locality.EQ(a.Locality), + models.SelectWhere.Addresses.Number.EQ(a.Number), + models.SelectWhere.Addresses.PostalCode.EQ(a.PostalCode), + models.SelectWhere.Addresses.Region.EQ(a.Region), + models.SelectWhere.Addresses.Street.EQ(a.Street), + models.SelectWhere.Addresses.Unit.EQ(a.Unit), + ).One(ctx, txn) + if err == nil { + return address, nil + } + id, err := insertAddress(ctx, txn, a, l) + if err != nil { + return nil, fmt.Errorf("insert address: %w", err) + } + return &models.Address{ + Country: a.Country, + Created: time.Now(), + Gid: a.GID, + H3cell: "", + ID: *id, + Locality: a.Locality, + Location: "", + PostalCode: a.PostalCode, + Street: a.Street, + Unit: a.Unit, + Region: a.Region, + Number: a.Number, + }, nil +} + +func ensureAddressFromFeature(ctx context.Context, txn bob.Executor, feature stadia.GeocodeFeature) (int32, error) { + if feature.Geometry.Type != "Point" { + return 0, fmt.Errorf("Can't hanlde stadia geometry %s", feature.Geometry.Type) + } + lat := feature.Geometry.Coordinates[1] + lng := feature.Geometry.Coordinates[0] + cell, err := h3utils.GetCell(lng, lat, 15) + if err != nil { + return 0, fmt.Errorf("failed to convert lat %f lng %f to h3 cell", lat, lng) + } + type _row struct { + ID int32 `db:"id"` + } + row, err := bob.One(ctx, txn, psql.Insert( + im.Into("address", "country", "created", "gid", "h3cell", "id", "locality", "location", "number_", "postal_code", "region", "street", "unit"), + im.Values( + psql.Arg(feature.CountryCode()), + psql.Arg(time.Now()), + psql.Arg(feature.Properties.GID), + psql.Arg(cell.String()), + psql.Raw("DEFAULT"), + psql.Arg(feature.Locality()), + psql.F("ST_Point", lng, lat, 4326), + psql.Arg(feature.Number()), + psql.Arg(feature.PostalCode()), + psql.Arg(feature.Region()), + psql.Arg(feature.Street()), + psql.Raw("''"), + ), + im.Returning("id"), + ), scan.StructMapper[_row]()) + log.Info().Int32("id", row.ID).Msg("inserted address") + if err != nil { + return 0, fmt.Errorf("insert: %w", err) + } + return row.ID, nil +} +func insertAddress(ctx context.Context, txn bob.Executor, address types.Address, location types.Location) (*int32, error) { + cell, err := h3utils.GetCell(location.Longitude, location.Latitude, 15) + if err != nil { + return nil, fmt.Errorf("failed to convert lat %f lng %f to h3 cell", location.Longitude, location.Latitude) + } + type _row struct { + ID int32 `db:"id"` + } + row, err := bob.One(ctx, txn, psql.Insert( + im.Into("address", "country", "created", "gid", "h3cell", "id", "locality", "location", "number_", "postal_code", "region", "street", "unit"), + im.Values( + psql.Arg(address.Country), + psql.Arg(time.Now()), + psql.Arg(address.GID), + psql.Arg(cell), + psql.Raw("DEFAULT"), + psql.Arg(address.Locality), + psql.F("ST_Point", location.Longitude, location.Latitude, 4326), + psql.Arg(address.Number), + psql.Arg(address.PostalCode), + psql.Arg(address.Region), + psql.Arg(address.Street), + psql.Raw("''"), + ), + im.Returning("id"), + ), scan.StructMapper[_row]()) + if err != nil { + return nil, fmt.Errorf("insert: %w", err) + } + + return &row.ID, nil +} +func insertAddresses(ctx context.Context, txn bob.Executor, features []stadia.GeocodeFeature) error { + return nil +} diff --git a/platform/geocode/by_gid.go b/platform/geocode/by_gid.go index a1936502..c7ae32c9 100644 --- a/platform/geocode/by_gid.go +++ b/platform/geocode/by_gid.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/Gleipnir-Technology/nidus-sync/db" "github.com/Gleipnir-Technology/nidus-sync/h3utils" "github.com/Gleipnir-Technology/nidus-sync/platform/types" "github.com/Gleipnir-Technology/nidus-sync/stadia" @@ -29,10 +30,15 @@ func ByGID(ctx context.Context, gid string) (*GeocodeResult, error) { if err != nil { return nil, fmt.Errorf("latlngtocell: %w", err) } + id, err := ensureAddressFromFeature(ctx, db.PGInstance.BobDB, feature) + if err != nil { + return nil, fmt.Errorf("insert address: %w", err) + } return &GeocodeResult{ Address: types.Address{ Country: feature.Properties.Context.ISO3166A3, GID: feature.Properties.GID, + ID: &id, Locality: feature.Properties.Context.WhosOnFirst.Locality.Name, Number: feature.Properties.AddressComponents.Number, PostalCode: feature.Properties.AddressComponents.PostalCode, diff --git a/platform/geocode/geocode.go b/platform/geocode/geocode.go index 928778cd..66402bb0 100644 --- a/platform/geocode/geocode.go +++ b/platform/geocode/geocode.go @@ -9,7 +9,6 @@ import ( "github.com/Gleipnir-Technology/bob" "github.com/Gleipnir-Technology/bob/dialect/psql" - "github.com/Gleipnir-Technology/bob/dialect/psql/im" "github.com/Gleipnir-Technology/bob/dialect/psql/sm" bobtypes "github.com/Gleipnir-Technology/bob/types" "github.com/Gleipnir-Technology/nidus-sync/db" @@ -18,7 +17,6 @@ import ( "github.com/Gleipnir-Technology/nidus-sync/platform/types" "github.com/Gleipnir-Technology/nidus-sync/stadia" "github.com/aarondl/opt/omit" - "github.com/stephenafamo/scan" //"github.com/rs/zerolog/log" "github.com/uber/h3-go/v4" "resty.dev/v3" @@ -52,127 +50,6 @@ func restyMiddleware(rclient *resty.Client, response *resty.Response) error { return nil } -// Ensure the provided address exists. If it doesn't add it to the database. -func EnsureAddress(ctx context.Context, txn bob.Executor, a types.Address, l types.Location) (*models.Address, error) { - address, err := models.Addresses.Query( - models.SelectWhere.Addresses.Country.EQ(a.CountryEnum()), - models.SelectWhere.Addresses.Locality.EQ(a.Locality), - models.SelectWhere.Addresses.Number.EQ(a.Number), - models.SelectWhere.Addresses.PostalCode.EQ(a.PostalCode), - models.SelectWhere.Addresses.Region.EQ(a.Region), - models.SelectWhere.Addresses.Street.EQ(a.Street), - models.SelectWhere.Addresses.Unit.EQ(a.Unit), - ).One(ctx, txn) - if err == nil { - return address, nil - } - cell, err := h3utils.GetCell(l.Longitude, l.Latitude, 15) - if err != nil { - return nil, fmt.Errorf("failed to convert lat %f lng %f to h3 cell", l.Longitude, l.Latitude) - } - type _row struct { - ID int32 `db:"id"` - } - created := time.Now() - row, err := bob.One(ctx, txn, psql.Insert( - im.Into("address", "country", "created", "gid", "h3cell", "id", "locality", "location", "number_", "postal_code", "region", "street", "unit"), - im.Values( - psql.Arg(a.CountryEnum()), - psql.Arg(created), - psql.Arg(a.GID), - psql.Arg(cell), - psql.Raw("DEFAULT"), - psql.Arg(a.Locality), - psql.F("ST_Point", l.Longitude, l.Latitude, 4326), - psql.Arg(a.Number), - psql.Arg(a.PostalCode), - psql.Arg(a.Region), - psql.Arg(a.Street), - psql.Raw("''"), - ), - im.Returning("id"), - ), scan.StructMapper[_row]()) - if err != nil { - return nil, fmt.Errorf("insert: %w", err) - } - return &models.Address{ - Country: a.CountryEnum(), - Created: created, - Gid: a.GID, - H3cell: "", - ID: row.ID, - Locality: a.Locality, - Location: "", - PostalCode: a.PostalCode, - Street: a.Street, - Unit: a.Unit, - Region: a.Region, - Number: a.Number, - }, nil -} - -// Either get an address that matches, or create a new address. Either way, return an address -// This will make a call to a structured geocode service, so it's slow. -func EnsureAddressWithGeocode(ctx context.Context, txn bob.Executor, org *models.Organization, a types.Address) (*models.Address, error) { - address, err := models.Addresses.Query( - models.SelectWhere.Addresses.Country.EQ(a.CountryEnum()), - models.SelectWhere.Addresses.Locality.EQ(a.Locality), - models.SelectWhere.Addresses.Number.EQ(a.Number), - models.SelectWhere.Addresses.PostalCode.EQ(a.PostalCode), - models.SelectWhere.Addresses.Region.EQ(a.Region), - models.SelectWhere.Addresses.Street.EQ(a.Street), - models.SelectWhere.Addresses.Unit.EQ(a.Unit), - ).One(ctx, txn) - if err == nil { - return address, nil - } - // Geocode - geo, err := GeocodeStructured(ctx, org, a) - if err != nil { - return nil, fmt.Errorf("geocode: %w", err) - } - - type _row struct { - ID int32 `db:"id"` - } - created := time.Now() - row, err := bob.One(ctx, txn, psql.Insert( - im.Into("address", "country", "created", "gid", "h3cell", "id", "locality", "location", "number_", "postal_code", "region", "street", "unit"), - im.Values( - psql.Arg(geo.Address.Country), - psql.Arg(created), - psql.Arg(geo.Address.GID), - psql.Arg(geo.Cell), - psql.Raw("DEFAULT"), - psql.Arg(geo.Address.Locality), - psql.F("ST_Point", geo.Location.Longitude, geo.Location.Latitude, 4326), - psql.Arg(geo.Address.Number), - psql.Arg(geo.Address.PostalCode), - psql.Arg(geo.Address.Region), - psql.Arg(geo.Address.Street), - psql.Raw("''"), - ), - im.Returning("id"), - ), scan.StructMapper[_row]()) - if err != nil { - return nil, fmt.Errorf("insert: %w", err) - } - - return &models.Address{ - Country: geo.Address.CountryEnum(), - Created: created, - Gid: geo.Address.GID, - H3cell: "", - ID: row.ID, - Locality: geo.Address.Locality, - Location: "", - PostalCode: geo.Address.PostalCode, - Street: geo.Address.Street, - Unit: geo.Address.Unit, - Region: geo.Address.Region, - Number: geo.Address.Number, - }, nil -} func GeocodeRaw(ctx context.Context, org *models.Organization, address string) (*GeocodeResult, error) { req := stadia.RequestGeocodeRaw{ Text: address, @@ -182,6 +59,7 @@ func GeocodeRaw(ctx context.Context, org *models.Organization, address string) ( if err != nil { return nil, fmt.Errorf("client raw geocode failure on %s: %w", address, err) } + insertAddresses(ctx, db.PGInstance.BobDB, resp.Features) return toGeocodeResult(*resp, address) } func GeocodeStructured(ctx context.Context, org *models.Organization, a types.Address) (*GeocodeResult, error) { @@ -198,6 +76,7 @@ func GeocodeStructured(ctx context.Context, org *models.Organization, a types.Ad if err != nil { return nil, fmt.Errorf("client structured geocode failure on %s: %w", a.String(), err) } + insertAddresses(ctx, db.PGInstance.BobDB, resp.Features) return toGeocodeResult(*resp, a.String()) } func ReverseGeocode(ctx context.Context, location types.Location) (*GeocodeResult, error) { @@ -209,6 +88,7 @@ func ReverseGeocode(ctx context.Context, location types.Location) (*GeocodeResul if err != nil { return nil, fmt.Errorf("client reverse geocode failure on %s: %w", location.String(), err) } + insertAddresses(ctx, db.PGInstance.BobDB, resp.Features) return toGeocodeResult(*resp, location.String()) } @@ -264,10 +144,13 @@ func toGeocodeResult(resp stadia.GeocodeResponse, address_msg string) (*GeocodeR } // Get the parcel for a given address, if one can be found -func GetParcel(ctx context.Context, txn bob.Executor, a *models.Address) (*models.Parcel, error) { +func GetParcel(ctx context.Context, txn bob.Executor, a types.Address) (*models.Parcel, error) { + if a.ID == nil { + return nil, fmt.Errorf("nil address ID") + } result, err := models.Parcels.Query( sm.InnerJoin("address").On(psql.F("ST_Contains", psql.Raw("parcel.geometry"), psql.Raw("address.location"))), - models.SelectWhere.Addresses.ID.EQ(a.ID), + models.SelectWhere.Addresses.ID.EQ(*a.ID), ).One(ctx, txn) if err != nil { if err.Error() == "sql: no rows in result set" { diff --git a/platform/types/address.go b/platform/types/address.go index f07eb6d2..ccedebd4 100644 --- a/platform/types/address.go +++ b/platform/types/address.go @@ -3,8 +3,8 @@ package types import ( "fmt" - "github.com/Gleipnir-Technology/nidus-sync/db/enums" "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/rs/zerolog/log" ) type Address struct { @@ -24,12 +24,10 @@ type Address struct { func (a Address) String() string { return fmt.Sprintf("%s %s, %s, %s, %s, %s", a.Number, a.Street, a.Locality, a.Region, a.PostalCode, a.Country) } -func (a Address) CountryEnum() enums.Countrytype { - return enums.CountrytypeUsa -} func AddressFromModel(m *models.Address) Address { + log.Debug().Int32("id", m.ID).Float64("lat", m.LocationY.GetOr(0.0)).Float64("lng", m.LocationX.GetOr(0.0)).Msg("converting address") return Address{ - Country: m.Country.String(), + Country: m.Country, GID: m.Gid, ID: &m.ID, Locality: m.Locality, diff --git a/resource/compliance.go b/resource/compliance.go index 0932534d..8138b684 100644 --- a/resource/compliance.go +++ b/resource/compliance.go @@ -12,7 +12,6 @@ import ( //"github.com/Gleipnir-Technology/nidus-sync/html" nhttp "github.com/Gleipnir-Technology/nidus-sync/http" "github.com/Gleipnir-Technology/nidus-sync/platform" - "github.com/Gleipnir-Technology/nidus-sync/platform/types" //"github.com/rs/zerolog/log" )