Push geocoding down a layer

This makes it possible to always save address information from our
geocoder.
This commit is contained in:
Eli Ribble 2026-03-04 18:29:52 +00:00
parent 80e14568c6
commit daa8cb1748
No known key found for this signature in database
26 changed files with 576 additions and 431 deletions

View file

@ -10,17 +10,8 @@ var AddressErrors = &addressErrors{
columns: []string{"id"},
s: "address_pkey",
},
ErrUniqueAddressCountryLocalityUnitNumber_StreetKey: &UniqueConstraintError{
schema: "",
table: "address",
columns: []string{"country", "locality", "unit", "number_", "street"},
s: "address_country_locality_unit_number__street_key",
},
}
type addressErrors struct {
ErrUniqueAddressPkey *UniqueConstraintError
ErrUniqueAddressCountryLocalityUnitNumber_StreetKey *UniqueConstraintError
}

View file

@ -69,15 +69,6 @@ var Addresses = Table[
Generated: false,
AutoIncr: false,
},
Number: column{
Name: "number_",
DBType: "integer",
Default: "",
Comment: "",
Nullable: false,
Generated: false,
AutoIncr: false,
},
PostalCode: column{
Name: "postal_code",
DBType: "text",
@ -114,6 +105,15 @@ var Addresses = Table[
Generated: false,
AutoIncr: false,
},
Number: column{
Name: "number_",
DBType: "text",
Default: "",
Comment: "",
Nullable: false,
Generated: false,
AutoIncr: false,
},
},
Indexes: addressIndexes{
AddressPkey: index{
@ -133,43 +133,6 @@ var Addresses = Table[
Where: "",
Include: []string{},
},
AddressCountryLocalityUnitNumberStreetKey: index{
Type: "btree",
Name: "address_country_locality_unit_number__street_key",
Columns: []indexColumn{
{
Name: "country",
Desc: null.FromCond(false, true),
IsExpression: false,
},
{
Name: "locality",
Desc: null.FromCond(false, true),
IsExpression: false,
},
{
Name: "unit",
Desc: null.FromCond(false, true),
IsExpression: false,
},
{
Name: "number_",
Desc: null.FromCond(false, true),
IsExpression: false,
},
{
Name: "street",
Desc: null.FromCond(false, true),
IsExpression: false,
},
},
Unique: true,
Comment: "",
NullsFirst: []bool{false, false, false, false, false},
NullsDistinct: false,
Where: "",
Include: []string{},
},
IdxAddressGeom: index{
Type: "gist",
Name: "idx_address_geom",
@ -194,14 +157,6 @@ var Addresses = Table[
Comment: "",
},
Uniques: addressUniques{
AddressCountryLocalityUnitNumberStreetKey: constraint{
Name: "address_country_locality_unit_number__street_key",
Columns: []string{"country", "locality", "unit", "number_", "street"},
Comment: "",
},
},
Comment: "",
}
@ -212,28 +167,27 @@ type addressColumns struct {
H3cell column
ID column
Locality column
Number column
PostalCode column
Street column
Unit column
Region column
Number column
}
func (c addressColumns) AsSlice() []column {
return []column{
c.Country, c.Created, c.Geom, c.H3cell, c.ID, c.Locality, c.Number, c.PostalCode, c.Street, c.Unit, c.Region,
c.Country, c.Created, c.Geom, c.H3cell, c.ID, c.Locality, c.PostalCode, c.Street, c.Unit, c.Region, c.Number,
}
}
type addressIndexes struct {
AddressPkey index
AddressCountryLocalityUnitNumberStreetKey index
IdxAddressGeom index
AddressPkey index
IdxAddressGeom index
}
func (i addressIndexes) AsSlice() []index {
return []index{
i.AddressPkey, i.AddressCountryLocalityUnitNumberStreetKey, i.IdxAddressGeom,
i.AddressPkey, i.IdxAddressGeom,
}
}
@ -243,14 +197,10 @@ func (f addressForeignKeys) AsSlice() []foreignKey {
return []foreignKey{}
}
type addressUniques struct {
AddressCountryLocalityUnitNumberStreetKey constraint
}
type addressUniques struct{}
func (u addressUniques) AsSlice() []constraint {
return []constraint{
u.AddressCountryLocalityUnitNumberStreetKey,
}
return []constraint{}
}
type addressChecks struct{}

View file

@ -988,11 +988,13 @@ func (e *FileuploadCsvtype) Scan(value any) error {
// Enum values for FileuploadFilestatustype
const (
FileuploadFilestatustypeError FileuploadFilestatustype = "error"
FileuploadFilestatustypeParsed FileuploadFilestatustype = "parsed"
FileuploadFilestatustypeUploaded FileuploadFilestatustype = "uploaded"
FileuploadFilestatustypeCommitted FileuploadFilestatustype = "committed"
FileuploadFilestatustypeDiscarded FileuploadFilestatustype = "discarded"
FileuploadFilestatustypeError FileuploadFilestatustype = "error"
FileuploadFilestatustypeParsed FileuploadFilestatustype = "parsed"
FileuploadFilestatustypeUploaded FileuploadFilestatustype = "uploaded"
FileuploadFilestatustypeParsing FileuploadFilestatustype = "parsing"
FileuploadFilestatustypeCommitting FileuploadFilestatustype = "committing"
FileuploadFilestatustypeCommitted FileuploadFilestatustype = "committed"
FileuploadFilestatustypeDiscarded FileuploadFilestatustype = "discarded"
)
func AllFileuploadFilestatustype() []FileuploadFilestatustype {
@ -1000,6 +1002,8 @@ func AllFileuploadFilestatustype() []FileuploadFilestatustype {
FileuploadFilestatustypeError,
FileuploadFilestatustypeParsed,
FileuploadFilestatustypeUploaded,
FileuploadFilestatustypeParsing,
FileuploadFilestatustypeCommitting,
FileuploadFilestatustypeCommitted,
FileuploadFilestatustypeDiscarded,
}
@ -1016,6 +1020,8 @@ func (e FileuploadFilestatustype) Valid() bool {
case FileuploadFilestatustypeError,
FileuploadFilestatustypeParsed,
FileuploadFilestatustypeUploaded,
FileuploadFilestatustypeParsing,
FileuploadFilestatustypeCommitting,
FileuploadFilestatustypeCommitted,
FileuploadFilestatustypeDiscarded:
return true

View file

@ -42,11 +42,11 @@ type AddressTemplate struct {
H3cell func() string
ID func() int32
Locality func() string
Number func() int32
PostalCode func() string
Street func() string
Unit func() string
Region func() string
Number func() string
r addressR
f *Factory
@ -145,10 +145,6 @@ func (o AddressTemplate) BuildSetter() *models.AddressSetter {
val := o.Locality()
m.Locality = omit.From(val)
}
if o.Number != nil {
val := o.Number()
m.Number = omit.From(val)
}
if o.PostalCode != nil {
val := o.PostalCode()
m.PostalCode = omit.From(val)
@ -165,6 +161,10 @@ func (o AddressTemplate) BuildSetter() *models.AddressSetter {
val := o.Region()
m.Region = omit.From(val)
}
if o.Number != nil {
val := o.Number()
m.Number = omit.From(val)
}
return m
}
@ -205,9 +205,6 @@ func (o AddressTemplate) Build() *models.Address {
if o.Locality != nil {
m.Locality = o.Locality()
}
if o.Number != nil {
m.Number = o.Number()
}
if o.PostalCode != nil {
m.PostalCode = o.PostalCode()
}
@ -220,6 +217,9 @@ func (o AddressTemplate) Build() *models.Address {
if o.Region != nil {
m.Region = o.Region()
}
if o.Number != nil {
m.Number = o.Number()
}
o.setModelRels(m)
@ -260,10 +260,6 @@ func ensureCreatableAddress(m *models.AddressSetter) {
val := random_string(nil)
m.Locality = omit.From(val)
}
if !(m.Number.IsValue()) {
val := random_int32(nil)
m.Number = omit.From(val)
}
if !(m.PostalCode.IsValue()) {
val := random_string(nil)
m.PostalCode = omit.From(val)
@ -280,6 +276,10 @@ func ensureCreatableAddress(m *models.AddressSetter) {
val := random_string(nil)
m.Region = omit.From(val)
}
if !(m.Number.IsValue()) {
val := random_string(nil)
m.Number = omit.From(val)
}
}
// insertOptRels creates and inserts any optional the relationships on *models.Address
@ -445,11 +445,11 @@ func (m addressMods) RandomizeAllColumns(f *faker.Faker) AddressMod {
AddressMods.RandomH3cell(f),
AddressMods.RandomID(f),
AddressMods.RandomLocality(f),
AddressMods.RandomNumber(f),
AddressMods.RandomPostalCode(f),
AddressMods.RandomStreet(f),
AddressMods.RandomUnit(f),
AddressMods.RandomRegion(f),
AddressMods.RandomNumber(f),
}
}
@ -639,37 +639,6 @@ func (m addressMods) RandomLocality(f *faker.Faker) AddressMod {
})
}
// Set the model columns to this value
func (m addressMods) Number(val int32) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = func() int32 { return val }
})
}
// Set the Column from the function
func (m addressMods) NumberFunc(f func() int32) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = f
})
}
// Clear any values for the column
func (m addressMods) UnsetNumber() AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
func (m addressMods) RandomNumber(f *faker.Faker) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = func() int32 {
return random_int32(f)
}
})
}
// Set the model columns to this value
func (m addressMods) PostalCode(val string) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
@ -794,6 +763,37 @@ func (m addressMods) RandomRegion(f *faker.Faker) AddressMod {
})
}
// Set the model columns to this value
func (m addressMods) Number(val string) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = func() string { return val }
})
}
// Set the Column from the function
func (m addressMods) NumberFunc(f func() string) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = f
})
}
// Clear any values for the column
func (m addressMods) UnsetNumber() AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
func (m addressMods) RandomNumber(f *faker.Faker) AddressMod {
return AddressModFunc(func(_ context.Context, o *AddressTemplate) {
o.Number = func() string {
return random_string(f)
}
})
}
func (m addressMods) WithParentsCascading() AddressMod {
return AddressModFunc(func(ctx context.Context, o *AddressTemplate) {
if isDone, _ := addressWithParentsCascadingCtx.Value(ctx); isDone {

View file

@ -143,11 +143,11 @@ func (f *Factory) FromExistingAddress(m *models.Address) *AddressTemplate {
o.H3cell = func() string { return m.H3cell }
o.ID = func() int32 { return m.ID }
o.Locality = func() string { return m.Locality }
o.Number = func() int32 { return m.Number }
o.PostalCode = func() string { return m.PostalCode }
o.Street = func() string { return m.Street }
o.Unit = func() string { return m.Unit }
o.Region = func() string { return m.Region }
o.Number = func() string { return m.Number }
ctx := context.Background()
if len(m.R.Mailers) > 0 {

View file

@ -0,0 +1,4 @@
-- +goose Up
ALTER TYPE fileupload.FileStatusType ADD VALUE 'parsing' AFTER 'uploaded';
ALTER TYPE fileupload.FileStatusType ADD VALUE 'committing' AFTER 'parsing';
-- +goose Down

View file

@ -0,0 +1,10 @@
-- +goose Up
ALTER TABLE address DROP COLUMN number_;
ALTER TABLE address ADD COLUMN number_ TEXT;
UPDATE address SET number_ = '';
ALTER TABLE address ALTER COLUMN number_ SET NOT NULL;
-- +goose Down
ALTER TABLE address DROP COLUMN number_;
ALTER TABLE address ADD COLUMN number_ INTEGER;
UPDATE address SET number_ = 0;
ALTER TABLE address ALTER COLUMN number_ SET NOT NULL;

View file

@ -31,11 +31,11 @@ type Address struct {
H3cell string `db:"h3cell" `
ID int32 `db:"id,pk" `
Locality string `db:"locality" `
Number int32 `db:"number_" `
PostalCode string `db:"postal_code" `
Street string `db:"street" `
Unit string `db:"unit" `
Region string `db:"region" `
Number string `db:"number_" `
R addressR `db:"-" `
@ -62,7 +62,7 @@ type addressR struct {
func buildAddressColumns(alias string) addressColumns {
return addressColumns{
ColumnsExpr: expr.NewColumnsExpr(
"country", "created", "geom", "h3cell", "id", "locality", "number_", "postal_code", "street", "unit", "region",
"country", "created", "geom", "h3cell", "id", "locality", "postal_code", "street", "unit", "region", "number_",
).WithParent("address"),
tableAlias: alias,
Country: psql.Quote(alias, "country"),
@ -71,11 +71,11 @@ func buildAddressColumns(alias string) addressColumns {
H3cell: psql.Quote(alias, "h3cell"),
ID: psql.Quote(alias, "id"),
Locality: psql.Quote(alias, "locality"),
Number: psql.Quote(alias, "number_"),
PostalCode: psql.Quote(alias, "postal_code"),
Street: psql.Quote(alias, "street"),
Unit: psql.Quote(alias, "unit"),
Region: psql.Quote(alias, "region"),
Number: psql.Quote(alias, "number_"),
}
}
@ -88,11 +88,11 @@ type addressColumns struct {
H3cell psql.Expression
ID psql.Expression
Locality psql.Expression
Number psql.Expression
PostalCode psql.Expression
Street psql.Expression
Unit psql.Expression
Region psql.Expression
Number psql.Expression
}
func (c addressColumns) Alias() string {
@ -113,11 +113,11 @@ type AddressSetter struct {
H3cell omit.Val[string] `db:"h3cell" `
ID omit.Val[int32] `db:"id,pk" `
Locality omit.Val[string] `db:"locality" `
Number omit.Val[int32] `db:"number_" `
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_" `
}
func (s AddressSetter) SetColumns() []string {
@ -140,9 +140,6 @@ func (s AddressSetter) SetColumns() []string {
if s.Locality.IsValue() {
vals = append(vals, "locality")
}
if s.Number.IsValue() {
vals = append(vals, "number_")
}
if s.PostalCode.IsValue() {
vals = append(vals, "postal_code")
}
@ -155,6 +152,9 @@ func (s AddressSetter) SetColumns() []string {
if s.Region.IsValue() {
vals = append(vals, "region")
}
if s.Number.IsValue() {
vals = append(vals, "number_")
}
return vals
}
@ -177,9 +177,6 @@ func (s AddressSetter) Overwrite(t *Address) {
if s.Locality.IsValue() {
t.Locality = s.Locality.MustGet()
}
if s.Number.IsValue() {
t.Number = s.Number.MustGet()
}
if s.PostalCode.IsValue() {
t.PostalCode = s.PostalCode.MustGet()
}
@ -192,6 +189,9 @@ func (s AddressSetter) Overwrite(t *Address) {
if s.Region.IsValue() {
t.Region = s.Region.MustGet()
}
if s.Number.IsValue() {
t.Number = s.Number.MustGet()
}
}
func (s *AddressSetter) Apply(q *dialect.InsertQuery) {
@ -237,32 +237,32 @@ func (s *AddressSetter) Apply(q *dialect.InsertQuery) {
vals[5] = psql.Raw("DEFAULT")
}
if s.Number.IsValue() {
vals[6] = psql.Arg(s.Number.MustGet())
if s.PostalCode.IsValue() {
vals[6] = psql.Arg(s.PostalCode.MustGet())
} else {
vals[6] = psql.Raw("DEFAULT")
}
if s.PostalCode.IsValue() {
vals[7] = psql.Arg(s.PostalCode.MustGet())
if s.Street.IsValue() {
vals[7] = psql.Arg(s.Street.MustGet())
} else {
vals[7] = psql.Raw("DEFAULT")
}
if s.Street.IsValue() {
vals[8] = psql.Arg(s.Street.MustGet())
if s.Unit.IsValue() {
vals[8] = psql.Arg(s.Unit.MustGet())
} else {
vals[8] = psql.Raw("DEFAULT")
}
if s.Unit.IsValue() {
vals[9] = psql.Arg(s.Unit.MustGet())
if s.Region.IsValue() {
vals[9] = psql.Arg(s.Region.MustGet())
} else {
vals[9] = psql.Raw("DEFAULT")
}
if s.Region.IsValue() {
vals[10] = psql.Arg(s.Region.MustGet())
if s.Number.IsValue() {
vals[10] = psql.Arg(s.Number.MustGet())
} else {
vals[10] = psql.Raw("DEFAULT")
}
@ -320,13 +320,6 @@ func (s AddressSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if s.Number.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "number_")...),
psql.Arg(s.Number),
}})
}
if s.PostalCode.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "postal_code")...),
@ -355,6 +348,13 @@ func (s AddressSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if s.Number.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "number_")...),
psql.Arg(s.Number),
}})
}
return exprs
}
@ -850,11 +850,11 @@ type addressWhere[Q psql.Filterable] struct {
H3cell psql.WhereMod[Q, string]
ID psql.WhereMod[Q, int32]
Locality psql.WhereMod[Q, string]
Number psql.WhereMod[Q, int32]
PostalCode psql.WhereMod[Q, string]
Street psql.WhereMod[Q, string]
Unit psql.WhereMod[Q, string]
Region psql.WhereMod[Q, string]
Number psql.WhereMod[Q, string]
}
func (addressWhere[Q]) AliasedAs(alias string) addressWhere[Q] {
@ -869,11 +869,11 @@ func buildAddressWhere[Q psql.Filterable](cols addressColumns) addressWhere[Q] {
H3cell: psql.Where[Q, string](cols.H3cell),
ID: psql.Where[Q, int32](cols.ID),
Locality: psql.Where[Q, string](cols.Locality),
Number: psql.Where[Q, int32](cols.Number),
PostalCode: psql.Where[Q, string](cols.PostalCode),
Street: psql.Where[Q, string](cols.Street),
Unit: psql.Where[Q, string](cols.Unit),
Region: psql.Where[Q, string](cols.Region),
Number: psql.Where[Q, string](cols.Number),
}
}