Bunch of work around assigning reports to districts

I added some DB schema to track logos and to relate reports to
organizations. I reworked how GPS data comes from EXIF data on images
because it wasn't working for JPEGs. I might have broken PNGs in the
process. Also made the config options for domain names more
standardized.
This commit is contained in:
Eli Ribble 2026-01-22 03:27:32 +00:00
parent 486a2d98c2
commit 61d8d14fc2
No known key found for this signature in database
41 changed files with 3029 additions and 337 deletions

View file

@ -78,46 +78,6 @@ func apiAudioContentPost(w http.ResponseWriter, r *http.Request, u *models.User)
w.WriteHeader(http.StatusOK)
}
func apiGetDistrict(w http.ResponseWriter, r *http.Request) {
var latStr, lngStr string
err := r.ParseForm()
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse GET form: %w", err)))
return
} else {
latStr = r.FormValue("lat")
lngStr = r.FormValue("lng")
}
lat, err := strconv.ParseFloat(latStr, 64)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse lat as float: %w", err)))
return
}
lng, err := strconv.ParseFloat(lngStr, 64)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse lng as float: %w", err)))
return
}
district, err := platform.DistrictForLocation(r.Context(), lng, lat)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to get district: %w", err)))
return
}
if district == nil {
http.NotFound(w, r)
return
}
d := ResponseDistrict{
Agency: district.Agency.GetOr(""),
Manager: district.GeneralMG.GetOr(""),
Phone: district.Phone1.GetOr(""),
Website: district.Website.GetOr(""),
}
if err := render.Render(w, r, d); err != nil {
render.Render(w, r, errRender(err))
}
}
func handleClientIos(w http.ResponseWriter, r *http.Request, u *models.User) {
var sinceStr string
err := r.ParseForm()

74
api/district.go Normal file
View file

@ -0,0 +1,74 @@
package api
import (
"fmt"
"net/http"
"strconv"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/platform"
"github.com/Gleipnir-Technology/nidus-sync/userfile"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
)
func apiGetDistrict(w http.ResponseWriter, r *http.Request) {
var latStr, lngStr string
err := r.ParseForm()
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse GET form: %w", err)))
return
} else {
latStr = r.FormValue("lat")
lngStr = r.FormValue("lng")
}
lat, err := strconv.ParseFloat(latStr, 64)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse lat as float: %w", err)))
return
}
lng, err := strconv.ParseFloat(lngStr, 64)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to parse lng as float: %w", err)))
return
}
district, _, err := platform.DistrictForLocation(r.Context(), lng, lat)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("Failed to get district: %w", err)))
return
}
if district == nil {
http.NotFound(w, r)
return
}
d := ResponseDistrict{
Agency: district.Agency.GetOr(""),
Manager: district.GeneralMG.GetOr(""),
Phone: district.Phone1.GetOr(""),
Website: district.Website.GetOr(""),
}
if err := render.Render(w, r, d); err != nil {
render.Render(w, r, errRender(err))
}
}
func apiGetDistrictLogo(w http.ResponseWriter, r *http.Request) {
id_str := chi.URLParam(r, "id")
org_id, err := strconv.ParseInt(id_str, 10, 32)
if err != nil {
render.Render(w, r, errRender(fmt.Errorf("%s is not a recognized organization ID: %w", id_str, err)))
return
}
ctx := r.Context()
org, err := models.FindOrganization(ctx, db.PGInstance.BobDB, int32(org_id))
if err != nil {
http.Error(w, "Organization not found", http.StatusNotFound)
return
}
if org.LogoUUID.IsNull() {
http.Error(w, "Logo not found", http.StatusNotFound)
return
}
userfile.ImageFileContentWriteLogo(w, org.LogoUUID.MustGet())
}

View file

@ -21,6 +21,7 @@ func AddRoutes(r chi.Router) {
// Unauthenticated endpoints
r.Get("/district", apiGetDistrict)
r.Get("/district/{id}/logo", apiGetDistrictLogo)
r.Post("/twilio/message", twilioMessagePost)
r.Post("/twilio/status", twilioStatusPost)
r.Post("/twilio/text", twilioTextPost)

@ -1 +1 @@
Subproject commit af786fabcc08ed506a23718a71aa0dd52ce047ac
Subproject commit 09fda12abb8af08b4d95ea519fdda73b5399bf63

View file

@ -72,7 +72,7 @@ func HandleOauthAccessCode(ctx context.Context, user *models.User, code string)
"grant_type": []string{"authorization_code"},
"code": []string{code},
"client_id": []string{config.ClientID},
"redirect_uri": []string{config.RedirectURL()},
"redirect_uri": []string{config.ArcGISOauthRedirectURL()},
}
req, err := http.NewRequest("POST", baseURL, strings.NewReader(form.Encode()))
@ -652,7 +652,7 @@ func refreshRefreshToken(ctx context.Context, oauth *models.OauthToken) error {
form := url.Values{
"grant_type": []string{"exchange_refresh_token"},
"client_id": []string{config.ClientID},
"redirect_uri": []string{config.RedirectURL()},
"redirect_uri": []string{config.ArcGISOauthRedirectURL()},
"refresh_token": []string{oauth.RefreshToken},
}

View file

@ -106,10 +106,10 @@ type emailResponse struct {
func contentEmailSubscriptionConfirmation(report_id string) contentEmailReportConfirmation {
return contentEmailReportConfirmation{
URLLogo: fmt.Sprintf("https://%s/static/img/nidus-logo-no-lettering-64.png", config.URLReport),
URLReportStatus: fmt.Sprintf("https://%s/status/%s", config.URLReport, report_id),
URLReportUnsubscribe: fmt.Sprintf("https://%s/report/%s/unsubscribe", config.URLReport, report_id),
URLViewInBrowser: fmt.Sprintf("https://%s/email/report/%s/subscription-confirmation", config.URLReport, report_id),
URLLogo: config.MakeURLReport("/static/img/nidus-logo-no-lettering-64.png"),
URLReportStatus: config.MakeURLReport("/status/%s", report_id),
URLReportUnsubscribe: config.MakeURLReport("/report/%s/unsubscribe", report_id),
URLViewInBrowser: config.MakeURLReport("/email/report/%s/subscription-confirmation", report_id),
}
}

View file

@ -2,9 +2,7 @@ package config
import (
"fmt"
"net/url"
"os"
"strconv"
"github.com/nyaruka/phonenumbers"
)
@ -13,7 +11,11 @@ var (
Bind string
ClientID string
ClientSecret string
DomainRMO string
DomainNidus string
DomainTegola string
Environment string
FilesDirectoryLogo string
FilesDirectoryPublic string
FilesDirectoryUser string
FieldseekerSchemaDirectory string
@ -23,47 +25,29 @@ var (
ForwardEmailReportUsername string
MapboxToken string
PGDSN string
RMODomain string
RMOPhoneNumber phonenumbers.PhoneNumber
URLReport string
URLSync string
URLTegola string
TwilioAuthToken string
TwilioAccountSID string
TwilioMessagingServiceSID string
)
// Build the ArcGIS authorization URL with PKCE
func BuildArcGISAuthURL(clientID string) string {
baseURL := "https://www.arcgis.com/sharing/rest/oauth2/authorize/"
params := url.Values{}
params.Add("client_id", clientID)
params.Add("redirect_uri", RedirectURL())
params.Add("response_type", "code")
//params.Add("code_challenge", generateCodeChallenge(codeVerifier))
//params.Add("code_challenge_method", "S256")
// See https://developers.arcgis.com/rest/users-groups-and-items/token/
// expiration is defined in minutes
var expiration int
if IsProductionEnvironment() {
// 2 weeks is the maximum allowed
expiration = 20160
} else {
expiration = 20
}
params.Add("expiration", strconv.Itoa(expiration))
return baseURL + "?" + params.Encode()
}
func IsProductionEnvironment() bool {
return Environment == "PRODUCTION"
}
func MakeURLSync(path string) string {
return fmt.Sprintf("https://%s%s", URLSync, path)
func makeURL(domain, path string, args ...interface{}) string {
pattern := "https://" + domain + path
return fmt.Sprintf(pattern, args...)
}
func MakeURLNidus(path string, args ...interface{}) string {
return makeURL(DomainNidus, path, args...)
}
func MakeURLReport(path string, args ...interface{}) string {
return makeURL(DomainRMO, path, args...)
}
func MakeURLTegola(path string, args ...interface{}) string {
return makeURL(DomainTegola, path, args...)
}
func Parse() (err error) {
@ -79,6 +63,18 @@ func Parse() (err error) {
if ClientSecret == "" {
return fmt.Errorf("You must specify a non-empty ARCGIS_CLIENT_SECRET")
}
DomainNidus = os.Getenv("DOMAIN_NIDUS")
if DomainNidus == "" {
return fmt.Errorf("You must specify a non-empty DOMAIN_NIDUS")
}
DomainRMO = os.Getenv("DOMAIN_RMO")
if DomainRMO == "" {
return fmt.Errorf("You must specify a non-empty DOMAIN_RMO")
}
DomainTegola = os.Getenv("DOMAIN_TEGOLA")
if DomainTegola == "" {
return fmt.Errorf("You must specify a non-empty DOMAIN_TEGOLA")
}
Environment = os.Getenv("ENVIRONMENT")
if Environment == "" {
return fmt.Errorf("You must specify a non-empty ENVIRONMENT")
@ -90,6 +86,10 @@ func Parse() (err error) {
if FieldseekerSchemaDirectory == "" {
return fmt.Errorf("You must specify a non-empty FIELDSEEKER_SCHEMA_DIRECTORY")
}
FilesDirectoryLogo = os.Getenv("FILES_DIRECTORY_LOGO")
if FilesDirectoryLogo == "" {
return fmt.Errorf("You must specify a non-empty FILES_DIRECTORY_LOGO")
}
FilesDirectoryPublic = os.Getenv("FILES_DIRECTORY_PUBLIC")
if FilesDirectoryPublic == "" {
return fmt.Errorf("You must specify a non-empty FILES_DIRECTORY_PUBLIC")
@ -122,10 +122,6 @@ func Parse() (err error) {
if PGDSN == "" {
return fmt.Errorf("You must specify a non-empty POSTGRES_DSN")
}
RMODomain = os.Getenv("RMO_DOMAIN")
if RMODomain == "" {
return fmt.Errorf("You must specify a non-empty RMO_DOMAIN")
}
rmo_phone_number := os.Getenv("RMO_PHONE_NUMBER")
if rmo_phone_number == "" {
return fmt.Errorf("You must specify a non-empty RMO_PHONE_NUMBER")
@ -136,18 +132,6 @@ func Parse() (err error) {
}
RMOPhoneNumber = *p
URLReport = os.Getenv("URL_REPORT")
if URLReport == "" {
return fmt.Errorf("You must specify a non-empty URL_REPORT")
}
URLSync = os.Getenv("URL_SYNC")
if URLSync == "" {
return fmt.Errorf("You must specify a non-empty URL_SYNC")
}
URLTegola = os.Getenv("URL_TEGOLA")
if URLTegola == "" {
return fmt.Errorf("You must specify a non-empty URL_TEGOLA")
}
TwilioAccountSID = os.Getenv("TWILIO_ACCOUNT_SID")
if TwilioAccountSID == "" {
return fmt.Errorf("You must specify a non-empty TWILIO_ACCOUNT_SID")
@ -163,6 +147,6 @@ func Parse() (err error) {
return nil
}
func RedirectURL() string {
return MakeURLSync("/arcgis/oauth/callback")
func ArcGISOauthRedirectURL() string {
return MakeURLNidus("/arcgis/oauth/callback")
}

View file

@ -4,6 +4,9 @@ aliases:
up_singular: "ArcgisUser"
down_plural: "arcgisusers"
down_singular: "arcgisuser"
organization:
relationships:
publicreport.pool.pool_organization_id_fkey: "PublicreportPool"
user_:
up_plural: "Users"
up_singular: "User"

View file

@ -78,6 +78,15 @@ var Organizations = Table[
Generated: false,
AutoIncr: false,
},
LogoUUID: column{
Name: "logo_uuid",
DBType: "uuid",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: organizationIndexes{
OrganizationPkey: index{
@ -172,11 +181,12 @@ type organizationColumns struct {
FieldseekerURL column
ImportDistrictGid column
Website column
LogoUUID column
}
func (c organizationColumns) AsSlice() []column {
return []column{
c.ID, c.Name, c.ArcgisID, c.ArcgisName, c.FieldseekerURL, c.ImportDistrictGid, c.Website,
c.ID, c.Name, c.ArcgisID, c.ArcgisName, c.FieldseekerURL, c.ImportDistrictGid, c.Website, c.LogoUUID,
}
}

View file

@ -258,6 +258,15 @@ var PublicreportNuisances = Table[
Generated: false,
AutoIncr: false,
},
OrganizationID: column{
Name: "organization_id",
DBType: "integer",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: publicreportNuisanceIndexes{
NuisancePkey: index{
@ -300,7 +309,17 @@ var PublicreportNuisances = Table[
Columns: []string{"id"},
Comment: "",
},
ForeignKeys: publicreportNuisanceForeignKeys{
PublicreportNuisanceNuisanceOrganizationIDFkey: foreignKey{
constraint: constraint{
Name: "publicreport.nuisance.nuisance_organization_id_fkey",
Columns: []string{"organization_id"},
Comment: "",
},
ForeignTable: "organization",
ForeignColumns: []string{"id"},
},
},
Uniques: publicreportNuisanceUniques{
NuisancePublicIDKey: constraint{
Name: "nuisance_public_id_key",
@ -340,11 +359,12 @@ type publicreportNuisanceColumns struct {
Address column
Location column
Status column
OrganizationID column
}
func (c publicreportNuisanceColumns) AsSlice() []column {
return []column{
c.ID, c.AdditionalInfo, c.Created, c.Duration, c.Email, c.InspectionType, c.SourceLocation, c.PreferredDateRange, c.PreferredTime, c.RequestCall, c.Severity, c.SourceContainer, c.SourceDescription, c.SourceRoof, c.SourceStagnant, c.TimeOfDayDay, c.TimeOfDayEarly, c.TimeOfDayEvening, c.TimeOfDayNight, c.PublicID, c.ReporterAddress, c.ReporterEmail, c.ReporterName, c.ReporterPhone, c.Address, c.Location, c.Status,
c.ID, c.AdditionalInfo, c.Created, c.Duration, c.Email, c.InspectionType, c.SourceLocation, c.PreferredDateRange, c.PreferredTime, c.RequestCall, c.Severity, c.SourceContainer, c.SourceDescription, c.SourceRoof, c.SourceStagnant, c.TimeOfDayDay, c.TimeOfDayEarly, c.TimeOfDayEvening, c.TimeOfDayNight, c.PublicID, c.ReporterAddress, c.ReporterEmail, c.ReporterName, c.ReporterPhone, c.Address, c.Location, c.Status, c.OrganizationID,
}
}
@ -359,10 +379,14 @@ func (i publicreportNuisanceIndexes) AsSlice() []index {
}
}
type publicreportNuisanceForeignKeys struct{}
type publicreportNuisanceForeignKeys struct {
PublicreportNuisanceNuisanceOrganizationIDFkey foreignKey
}
func (f publicreportNuisanceForeignKeys) AsSlice() []foreignKey {
return []foreignKey{}
return []foreignKey{
f.PublicreportNuisanceNuisanceOrganizationIDFkey,
}
}
type publicreportNuisanceUniques struct {

View file

@ -285,6 +285,15 @@ var PublicreportPools = Table[
Generated: false,
AutoIncr: false,
},
OrganizationID: column{
Name: "organization_id",
DBType: "integer",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: publicreportPoolIndexes{
PoolPkey: index{
@ -327,7 +336,17 @@ var PublicreportPools = Table[
Columns: []string{"id"},
Comment: "",
},
ForeignKeys: publicreportPoolForeignKeys{
PublicreportPoolPoolOrganizationIDFkey: foreignKey{
constraint: constraint{
Name: "publicreport.pool.pool_organization_id_fkey",
Columns: []string{"organization_id"},
Comment: "",
},
ForeignTable: "organization",
ForeignColumns: []string{"id"},
},
},
Uniques: publicreportPoolUniques{
PoolPublicIDKey: constraint{
Name: "pool_public_id_key",
@ -370,11 +389,12 @@ type publicreportPoolColumns struct {
ReporterPhone column
Subscribe column
Status column
OrganizationID column
}
func (c publicreportPoolColumns) AsSlice() []column {
return []column{
c.ID, c.AccessComments, c.AccessGate, c.AccessFence, c.AccessLocked, c.AccessDog, c.AccessOther, c.Address, c.AddressCountry, c.AddressPostCode, c.AddressPlace, c.AddressStreet, c.AddressRegion, c.Comments, c.Created, c.H3cell, c.HasAdult, c.HasLarvae, c.HasPupae, c.Location, c.MapZoom, c.OwnerEmail, c.OwnerName, c.OwnerPhone, c.PublicID, c.ReporterEmail, c.ReporterName, c.ReporterPhone, c.Subscribe, c.Status,
c.ID, c.AccessComments, c.AccessGate, c.AccessFence, c.AccessLocked, c.AccessDog, c.AccessOther, c.Address, c.AddressCountry, c.AddressPostCode, c.AddressPlace, c.AddressStreet, c.AddressRegion, c.Comments, c.Created, c.H3cell, c.HasAdult, c.HasLarvae, c.HasPupae, c.Location, c.MapZoom, c.OwnerEmail, c.OwnerName, c.OwnerPhone, c.PublicID, c.ReporterEmail, c.ReporterName, c.ReporterPhone, c.Subscribe, c.Status, c.OrganizationID,
}
}
@ -389,10 +409,14 @@ func (i publicreportPoolIndexes) AsSlice() []index {
}
}
type publicreportPoolForeignKeys struct{}
type publicreportPoolForeignKeys struct {
PublicreportPoolPoolOrganizationIDFkey foreignKey
}
func (f publicreportPoolForeignKeys) AsSlice() []foreignKey {
return []foreignKey{}
return []foreignKey{
f.PublicreportPoolPoolOrganizationIDFkey,
}
}
type publicreportPoolUniques struct {

View file

@ -105,6 +105,15 @@ var PublicreportQuicks = Table[
Generated: false,
AutoIncr: false,
},
OrganizationID: column{
Name: "organization_id",
DBType: "integer",
Default: "NULL",
Comment: "",
Nullable: true,
Generated: false,
AutoIncr: false,
},
},
Indexes: publicreportQuickIndexes{
QuickPkey: index{
@ -147,7 +156,17 @@ var PublicreportQuicks = Table[
Columns: []string{"id"},
Comment: "",
},
ForeignKeys: publicreportQuickForeignKeys{
PublicreportQuickQuickOrganizationIDFkey: foreignKey{
constraint: constraint{
Name: "publicreport.quick.quick_organization_id_fkey",
Columns: []string{"organization_id"},
Comment: "",
},
ForeignTable: "organization",
ForeignColumns: []string{"id"},
},
},
Uniques: publicreportQuickUniques{
QuickPublicIDKey: constraint{
Name: "quick_public_id_key",
@ -170,11 +189,12 @@ type publicreportQuickColumns struct {
ReporterPhone column
Address column
Status column
OrganizationID column
}
func (c publicreportQuickColumns) AsSlice() []column {
return []column{
c.ID, c.Created, c.Comments, c.Location, c.H3cell, c.PublicID, c.ReporterEmail, c.ReporterPhone, c.Address, c.Status,
c.ID, c.Created, c.Comments, c.Location, c.H3cell, c.PublicID, c.ReporterEmail, c.ReporterPhone, c.Address, c.Status, c.OrganizationID,
}
}
@ -189,10 +209,14 @@ func (i publicreportQuickIndexes) AsSlice() []index {
}
}
type publicreportQuickForeignKeys struct{}
type publicreportQuickForeignKeys struct {
PublicreportQuickQuickOrganizationIDFkey foreignKey
}
func (f publicreportQuickForeignKeys) AsSlice() []foreignKey {
return []foreignKey{}
return []foreignKey{
f.PublicreportQuickQuickOrganizationIDFkey,
}
}
type publicreportQuickUniques struct {

View file

@ -240,6 +240,9 @@ var (
organizationRelNoteAudiosCtx = newContextual[bool]("note_audio.organization.note_audio.note_audio_organization_id_fkey")
organizationRelNoteImagesCtx = newContextual[bool]("note_image.organization.note_image.note_image_organization_id_fkey")
organizationRelImportDistrictGidDistrictCtx = newContextual[bool]("import.district.organization.organization.organization_import_district_gid_fkey")
organizationRelNuisancesCtx = newContextual[bool]("organization.publicreport.nuisance.publicreport.nuisance.nuisance_organization_id_fkey")
organizationRelPublicreportPoolCtx = newContextual[bool]("organization.publicreport.pool.publicreport.pool.pool_organization_id_fkey")
organizationRelQuicksCtx = newContextual[bool]("organization.publicreport.quick.publicreport.quick.quick_organization_id_fkey")
organizationRelUserCtx = newContextual[bool]("organization.user_.user_.user__organization_id_fkey")
// Relationship Contexts for publicreport.image
@ -254,9 +257,11 @@ var (
// Relationship Contexts for publicreport.nuisance
publicreportNuisanceWithParentsCascadingCtx = newContextual[bool]("publicreportNuisanceWithParentsCascading")
publicreportNuisanceRelOrganizationCtx = newContextual[bool]("organization.publicreport.nuisance.publicreport.nuisance.nuisance_organization_id_fkey")
// Relationship Contexts for publicreport.pool
publicreportPoolWithParentsCascadingCtx = newContextual[bool]("publicreportPoolWithParentsCascading")
publicreportPoolRelOrganizationCtx = newContextual[bool]("organization.publicreport.pool.publicreport.pool.pool_organization_id_fkey")
publicreportPoolRelImagesCtx = newContextual[bool]("publicreport.image.publicreport.pool.publicreport.pool_image.pool_image_image_id_fkeypublicreport.pool_image.pool_image_pool_id_fkey")
// Relationship Contexts for publicreport.pool_image
@ -266,6 +271,7 @@ var (
// Relationship Contexts for publicreport.quick
publicreportQuickWithParentsCascadingCtx = newContextual[bool]("publicreportQuickWithParentsCascading")
publicreportQuickRelOrganizationCtx = newContextual[bool]("organization.publicreport.quick.publicreport.quick.quick_organization_id_fkey")
publicreportQuickRelImagesCtx = newContextual[bool]("publicreport.image.publicreport.quick.publicreport.quick_image.quick_image_image_id_fkeypublicreport.quick_image.quick_image_quick_id_fkey")
// Relationship Contexts for publicreport.quick_image

View file

@ -2550,6 +2550,7 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization
o.FieldseekerURL = func() null.Val[string] { return m.FieldseekerURL }
o.ImportDistrictGid = func() null.Val[int32] { return m.ImportDistrictGid }
o.Website = func() null.Val[string] { return m.Website }
o.LogoUUID = func() null.Val[uuid.UUID] { return m.LogoUUID }
ctx := context.Background()
if len(m.R.Containerrelates) > 0 {
@ -2648,6 +2649,15 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization
if m.R.ImportDistrictGidDistrict != nil {
OrganizationMods.WithExistingImportDistrictGidDistrict(m.R.ImportDistrictGidDistrict).Apply(ctx, o)
}
if len(m.R.Nuisances) > 0 {
OrganizationMods.AddExistingNuisances(m.R.Nuisances...).Apply(ctx, o)
}
if len(m.R.PublicreportPool) > 0 {
OrganizationMods.AddExistingPublicreportPool(m.R.PublicreportPool...).Apply(ctx, o)
}
if len(m.R.Quicks) > 0 {
OrganizationMods.AddExistingQuicks(m.R.Quicks...).Apply(ctx, o)
}
if len(m.R.User) > 0 {
OrganizationMods.AddExistingUser(m.R.User...).Apply(ctx, o)
}
@ -2775,6 +2785,12 @@ func (f *Factory) FromExistingPublicreportNuisance(m *models.PublicreportNuisanc
o.Address = func() string { return m.Address }
o.Location = func() null.Val[string] { return m.Location }
o.Status = func() enums.PublicreportReportstatustype { return m.Status }
o.OrganizationID = func() null.Val[int32] { return m.OrganizationID }
ctx := context.Background()
if m.R.Organization != nil {
PublicreportNuisanceMods.WithExistingOrganization(m.R.Organization).Apply(ctx, o)
}
return o
}
@ -2828,8 +2844,12 @@ func (f *Factory) FromExistingPublicreportPool(m *models.PublicreportPool) *Publ
o.ReporterPhone = func() string { return m.ReporterPhone }
o.Subscribe = func() bool { return m.Subscribe }
o.Status = func() enums.PublicreportReportstatustype { return m.Status }
o.OrganizationID = func() null.Val[int32] { return m.OrganizationID }
ctx := context.Background()
if m.R.Organization != nil {
PublicreportPoolMods.WithExistingOrganization(m.R.Organization).Apply(ctx, o)
}
if len(m.R.Images) > 0 {
PublicreportPoolMods.AddExistingImages(m.R.Images...).Apply(ctx, o)
}
@ -2899,8 +2919,12 @@ func (f *Factory) FromExistingPublicreportQuick(m *models.PublicreportQuick) *Pu
o.ReporterPhone = func() string { return m.ReporterPhone }
o.Address = func() string { return m.Address }
o.Status = func() enums.PublicreportReportstatustype { return m.Status }
o.OrganizationID = func() null.Val[int32] { return m.OrganizationID }
ctx := context.Background()
if m.R.Organization != nil {
PublicreportQuickMods.WithExistingOrganization(m.R.Organization).Apply(ctx, o)
}
if len(m.R.Images) > 0 {
PublicreportQuickMods.AddExistingImages(m.R.Images...).Apply(ctx, o)
}

View file

@ -11,6 +11,7 @@ import (
"github.com/aarondl/opt/null"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/google/uuid"
"github.com/jaswdr/faker/v2"
"github.com/stephenafamo/bob"
)
@ -43,6 +44,7 @@ type OrganizationTemplate struct {
FieldseekerURL func() null.Val[string]
ImportDistrictGid func() null.Val[int32]
Website func() null.Val[string]
LogoUUID func() null.Val[uuid.UUID]
r organizationR
f *Factory
@ -83,6 +85,9 @@ type organizationR struct {
NoteAudios []*organizationRNoteAudiosR
NoteImages []*organizationRNoteImagesR
ImportDistrictGidDistrict *organizationRImportDistrictGidDistrictR
Nuisances []*organizationRNuisancesR
PublicreportPool []*organizationRPublicreportPoolR
Quicks []*organizationRQuicksR
User []*organizationRUserR
}
@ -213,6 +218,18 @@ type organizationRNoteImagesR struct {
type organizationRImportDistrictGidDistrictR struct {
o *ImportDistrictTemplate
}
type organizationRNuisancesR struct {
number int
o *PublicreportNuisanceTemplate
}
type organizationRPublicreportPoolR struct {
number int
o *PublicreportPoolTemplate
}
type organizationRQuicksR struct {
number int
o *PublicreportQuickTemplate
}
type organizationRUserR struct {
number int
o *UserTemplate
@ -638,6 +655,45 @@ func (t OrganizationTemplate) setModelRels(o *models.Organization) {
o.R.ImportDistrictGidDistrict = rel
}
if t.r.Nuisances != nil {
rel := models.PublicreportNuisanceSlice{}
for _, r := range t.r.Nuisances {
related := r.o.BuildMany(r.number)
for _, rel := range related {
rel.OrganizationID = null.From(o.ID) // h2
rel.R.Organization = o
}
rel = append(rel, related...)
}
o.R.Nuisances = rel
}
if t.r.PublicreportPool != nil {
rel := models.PublicreportPoolSlice{}
for _, r := range t.r.PublicreportPool {
related := r.o.BuildMany(r.number)
for _, rel := range related {
rel.OrganizationID = null.From(o.ID) // h2
rel.R.Organization = o
}
rel = append(rel, related...)
}
o.R.PublicreportPool = rel
}
if t.r.Quicks != nil {
rel := models.PublicreportQuickSlice{}
for _, r := range t.r.Quicks {
related := r.o.BuildMany(r.number)
for _, rel := range related {
rel.OrganizationID = null.From(o.ID) // h2
rel.R.Organization = o
}
rel = append(rel, related...)
}
o.R.Quicks = rel
}
if t.r.User != nil {
rel := models.UserSlice{}
for _, r := range t.r.User {
@ -685,6 +741,10 @@ func (o OrganizationTemplate) BuildSetter() *models.OrganizationSetter {
val := o.Website()
m.Website = omitnull.FromNull(val)
}
if o.LogoUUID != nil {
val := o.LogoUUID()
m.LogoUUID = omitnull.FromNull(val)
}
return m
}
@ -728,6 +788,9 @@ func (o OrganizationTemplate) Build() *models.Organization {
if o.Website != nil {
m.Website = o.Website()
}
if o.LogoUUID != nil {
m.LogoUUID = o.LogoUUID()
}
o.setModelRels(m)
@ -1399,6 +1462,66 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu
}
isNuisancesDone, _ := organizationRelNuisancesCtx.Value(ctx)
if !isNuisancesDone && o.r.Nuisances != nil {
ctx = organizationRelNuisancesCtx.WithValue(ctx, true)
for _, r := range o.r.Nuisances {
if r.o.alreadyPersisted {
m.R.Nuisances = append(m.R.Nuisances, r.o.Build())
} else {
rel32, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachNuisances(ctx, exec, rel32...)
if err != nil {
return err
}
}
}
}
isPublicreportPoolDone, _ := organizationRelPublicreportPoolCtx.Value(ctx)
if !isPublicreportPoolDone && o.r.PublicreportPool != nil {
ctx = organizationRelPublicreportPoolCtx.WithValue(ctx, true)
for _, r := range o.r.PublicreportPool {
if r.o.alreadyPersisted {
m.R.PublicreportPool = append(m.R.PublicreportPool, r.o.Build())
} else {
rel33, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachPublicreportPool(ctx, exec, rel33...)
if err != nil {
return err
}
}
}
}
isQuicksDone, _ := organizationRelQuicksCtx.Value(ctx)
if !isQuicksDone && o.r.Quicks != nil {
ctx = organizationRelQuicksCtx.WithValue(ctx, true)
for _, r := range o.r.Quicks {
if r.o.alreadyPersisted {
m.R.Quicks = append(m.R.Quicks, r.o.Build())
} else {
rel34, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachQuicks(ctx, exec, rel34...)
if err != nil {
return err
}
}
}
}
isUserDone, _ := organizationRelUserCtx.Value(ctx)
if !isUserDone && o.r.User != nil {
ctx = organizationRelUserCtx.WithValue(ctx, true)
@ -1406,12 +1529,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu
if r.o.alreadyPersisted {
m.R.User = append(m.R.User, r.o.Build())
} else {
rel32, err := r.o.CreateMany(ctx, exec, r.number)
rel35, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachUser(ctx, exec, rel32...)
err = m.AttachUser(ctx, exec, rel35...)
if err != nil {
return err
}
@ -1518,6 +1641,7 @@ func (m organizationMods) RandomizeAllColumns(f *faker.Faker) OrganizationMod {
OrganizationMods.RandomFieldseekerURL(f),
OrganizationMods.RandomImportDistrictGid(f),
OrganizationMods.RandomWebsite(f),
OrganizationMods.RandomLogoUUID(f),
}
}
@ -1848,6 +1972,59 @@ func (m organizationMods) RandomWebsiteNotNull(f *faker.Faker) OrganizationMod {
})
}
// Set the model columns to this value
func (m organizationMods) LogoUUID(val null.Val[uuid.UUID]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.LogoUUID = func() null.Val[uuid.UUID] { return val }
})
}
// Set the Column from the function
func (m organizationMods) LogoUUIDFunc(f func() null.Val[uuid.UUID]) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.LogoUUID = f
})
}
// Clear any values for the column
func (m organizationMods) UnsetLogoUUID() OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.LogoUUID = 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) RandomLogoUUID(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.LogoUUID = func() null.Val[uuid.UUID] {
if f == nil {
f = &defaultFaker
}
val := random_uuid_UUID(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) RandomLogoUUIDNotNull(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.LogoUUID = func() null.Val[uuid.UUID] {
if f == nil {
f = &defaultFaker
}
val := random_uuid_UUID(f)
return null.From(val)
}
})
}
func (m organizationMods) WithParentsCascading() OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
if isDone, _ := organizationWithParentsCascadingCtx.Value(ctx); isDone {
@ -3380,6 +3557,150 @@ func (m organizationMods) WithoutNoteImages() OrganizationMod {
})
}
func (m organizationMods) WithNuisances(number int, related *PublicreportNuisanceTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Nuisances = []*organizationRNuisancesR{{
number: number,
o: related,
}}
})
}
func (m organizationMods) WithNewNuisances(number int, mods ...PublicreportNuisanceMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportNuisanceWithContext(ctx, mods...)
m.WithNuisances(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddNuisances(number int, related *PublicreportNuisanceTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Nuisances = append(o.r.Nuisances, &organizationRNuisancesR{
number: number,
o: related,
})
})
}
func (m organizationMods) AddNewNuisances(number int, mods ...PublicreportNuisanceMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportNuisanceWithContext(ctx, mods...)
m.AddNuisances(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddExistingNuisances(existingModels ...*models.PublicreportNuisance) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
for _, em := range existingModels {
o.r.Nuisances = append(o.r.Nuisances, &organizationRNuisancesR{
o: o.f.FromExistingPublicreportNuisance(em),
})
}
})
}
func (m organizationMods) WithoutNuisances() OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Nuisances = nil
})
}
func (m organizationMods) WithPublicreportPool(number int, related *PublicreportPoolTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.PublicreportPool = []*organizationRPublicreportPoolR{{
number: number,
o: related,
}}
})
}
func (m organizationMods) WithNewPublicreportPool(number int, mods ...PublicreportPoolMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportPoolWithContext(ctx, mods...)
m.WithPublicreportPool(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddPublicreportPool(number int, related *PublicreportPoolTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.PublicreportPool = append(o.r.PublicreportPool, &organizationRPublicreportPoolR{
number: number,
o: related,
})
})
}
func (m organizationMods) AddNewPublicreportPool(number int, mods ...PublicreportPoolMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportPoolWithContext(ctx, mods...)
m.AddPublicreportPool(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddExistingPublicreportPool(existingModels ...*models.PublicreportPool) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
for _, em := range existingModels {
o.r.PublicreportPool = append(o.r.PublicreportPool, &organizationRPublicreportPoolR{
o: o.f.FromExistingPublicreportPool(em),
})
}
})
}
func (m organizationMods) WithoutPublicreportPool() OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.PublicreportPool = nil
})
}
func (m organizationMods) WithQuicks(number int, related *PublicreportQuickTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Quicks = []*organizationRQuicksR{{
number: number,
o: related,
}}
})
}
func (m organizationMods) WithNewQuicks(number int, mods ...PublicreportQuickMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportQuickWithContext(ctx, mods...)
m.WithQuicks(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddQuicks(number int, related *PublicreportQuickTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Quicks = append(o.r.Quicks, &organizationRQuicksR{
number: number,
o: related,
})
})
}
func (m organizationMods) AddNewQuicks(number int, mods ...PublicreportQuickMod) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
related := o.f.NewPublicreportQuickWithContext(ctx, mods...)
m.AddQuicks(number, related).Apply(ctx, o)
})
}
func (m organizationMods) AddExistingQuicks(existingModels ...*models.PublicreportQuick) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
for _, em := range existingModels {
o.r.Quicks = append(o.r.Quicks, &organizationRQuicksR{
o: o.f.FromExistingPublicreportQuick(em),
})
}
})
}
func (m organizationMods) WithoutQuicks() OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.Quicks = nil
})
}
func (m organizationMods) WithUser(number int, related *UserTemplate) OrganizationMod {
return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) {
o.r.User = []*organizationRUserR{{

View file

@ -65,12 +65,22 @@ type PublicreportNuisanceTemplate struct {
Address func() string
Location func() null.Val[string]
Status func() enums.PublicreportReportstatustype
OrganizationID func() null.Val[int32]
r publicreportNuisanceR
f *Factory
alreadyPersisted bool
}
type publicreportNuisanceR struct {
Organization *publicreportNuisanceROrganizationR
}
type publicreportNuisanceROrganizationR struct {
o *OrganizationTemplate
}
// Apply mods to the PublicreportNuisanceTemplate
func (o *PublicreportNuisanceTemplate) Apply(ctx context.Context, mods ...PublicreportNuisanceMod) {
for _, mod := range mods {
@ -80,7 +90,14 @@ func (o *PublicreportNuisanceTemplate) Apply(ctx context.Context, mods ...Public
// setModelRels creates and sets the relationships on *models.PublicreportNuisance
// according to the relationships in the template. Nothing is inserted into the db
func (t PublicreportNuisanceTemplate) setModelRels(o *models.PublicreportNuisance) {}
func (t PublicreportNuisanceTemplate) setModelRels(o *models.PublicreportNuisance) {
if t.r.Organization != nil {
rel := t.r.Organization.o.Build()
rel.R.Nuisances = append(rel.R.Nuisances, o)
o.OrganizationID = null.From(rel.ID) // h2
o.R.Organization = rel
}
}
// BuildSetter returns an *models.PublicreportNuisanceSetter
// this does nothing with the relationship templates
@ -195,6 +212,10 @@ func (o PublicreportNuisanceTemplate) BuildSetter() *models.PublicreportNuisance
val := o.Status()
m.Status = omit.From(val)
}
if o.OrganizationID != nil {
val := o.OrganizationID()
m.OrganizationID = omitnull.FromNull(val)
}
return m
}
@ -298,6 +319,9 @@ func (o PublicreportNuisanceTemplate) Build() *models.PublicreportNuisance {
if o.Status != nil {
m.Status = o.Status()
}
if o.OrganizationID != nil {
m.OrganizationID = o.OrganizationID()
}
o.setModelRels(m)
@ -426,6 +450,25 @@ func ensureCreatablePublicreportNuisance(m *models.PublicreportNuisanceSetter) {
func (o *PublicreportNuisanceTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.PublicreportNuisance) error {
var err error
isOrganizationDone, _ := publicreportNuisanceRelOrganizationCtx.Value(ctx)
if !isOrganizationDone && o.r.Organization != nil {
ctx = publicreportNuisanceRelOrganizationCtx.WithValue(ctx, true)
if o.r.Organization.o.alreadyPersisted {
m.R.Organization = o.r.Organization.o.Build()
} else {
var rel0 *models.Organization
rel0, err = o.r.Organization.o.Create(ctx, exec)
if err != nil {
return err
}
err = m.AttachOrganization(ctx, exec, rel0)
if err != nil {
return err
}
}
}
return err
}
@ -545,6 +588,7 @@ func (m publicreportNuisanceMods) RandomizeAllColumns(f *faker.Faker) Publicrepo
PublicreportNuisanceMods.RandomAddress(f),
PublicreportNuisanceMods.RandomLocation(f),
PublicreportNuisanceMods.RandomStatus(f),
PublicreportNuisanceMods.RandomOrganizationID(f),
}
}
@ -1407,11 +1451,99 @@ func (m publicreportNuisanceMods) RandomStatus(f *faker.Faker) PublicreportNuisa
})
}
// Set the model columns to this value
func (m publicreportNuisanceMods) OrganizationID(val null.Val[int32]) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(_ context.Context, o *PublicreportNuisanceTemplate) {
o.OrganizationID = func() null.Val[int32] { return val }
})
}
// Set the Column from the function
func (m publicreportNuisanceMods) OrganizationIDFunc(f func() null.Val[int32]) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(_ context.Context, o *PublicreportNuisanceTemplate) {
o.OrganizationID = f
})
}
// Clear any values for the column
func (m publicreportNuisanceMods) UnsetOrganizationID() PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(_ context.Context, o *PublicreportNuisanceTemplate) {
o.OrganizationID = 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 publicreportNuisanceMods) RandomOrganizationID(f *faker.Faker) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(_ context.Context, o *PublicreportNuisanceTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(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 publicreportNuisanceMods) RandomOrganizationIDNotNull(f *faker.Faker) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(_ context.Context, o *PublicreportNuisanceTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(f)
return null.From(val)
}
})
}
func (m publicreportNuisanceMods) WithParentsCascading() PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(ctx context.Context, o *PublicreportNuisanceTemplate) {
if isDone, _ := publicreportNuisanceWithParentsCascadingCtx.Value(ctx); isDone {
return
}
ctx = publicreportNuisanceWithParentsCascadingCtx.WithValue(ctx, true)
{
related := o.f.NewOrganizationWithContext(ctx, OrganizationMods.WithParentsCascading())
m.WithOrganization(related).Apply(ctx, o)
}
})
}
func (m publicreportNuisanceMods) WithOrganization(rel *OrganizationTemplate) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(ctx context.Context, o *PublicreportNuisanceTemplate) {
o.r.Organization = &publicreportNuisanceROrganizationR{
o: rel,
}
})
}
func (m publicreportNuisanceMods) WithNewOrganization(mods ...OrganizationMod) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(ctx context.Context, o *PublicreportNuisanceTemplate) {
related := o.f.NewOrganizationWithContext(ctx, mods...)
m.WithOrganization(related).Apply(ctx, o)
})
}
func (m publicreportNuisanceMods) WithExistingOrganization(em *models.Organization) PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(ctx context.Context, o *PublicreportNuisanceTemplate) {
o.r.Organization = &publicreportNuisanceROrganizationR{
o: o.f.FromExistingOrganization(em),
}
})
}
func (m publicreportNuisanceMods) WithoutOrganization() PublicreportNuisanceMod {
return PublicreportNuisanceModFunc(func(ctx context.Context, o *PublicreportNuisanceTemplate) {
o.r.Organization = nil
})
}

View file

@ -68,6 +68,7 @@ type PublicreportPoolTemplate struct {
ReporterPhone func() string
Subscribe func() bool
Status func() enums.PublicreportReportstatustype
OrganizationID func() null.Val[int32]
r publicreportPoolR
f *Factory
@ -76,9 +77,13 @@ type PublicreportPoolTemplate struct {
}
type publicreportPoolR struct {
Organization *publicreportPoolROrganizationR
Images []*publicreportPoolRImagesR
}
type publicreportPoolROrganizationR struct {
o *OrganizationTemplate
}
type publicreportPoolRImagesR struct {
number int
o *PublicreportImageTemplate
@ -94,6 +99,13 @@ func (o *PublicreportPoolTemplate) Apply(ctx context.Context, mods ...Publicrepo
// setModelRels creates and sets the relationships on *models.PublicreportPool
// according to the relationships in the template. Nothing is inserted into the db
func (t PublicreportPoolTemplate) setModelRels(o *models.PublicreportPool) {
if t.r.Organization != nil {
rel := t.r.Organization.o.Build()
rel.R.PublicreportPool = append(rel.R.PublicreportPool, o)
o.OrganizationID = null.From(rel.ID) // h2
o.R.Organization = rel
}
if t.r.Images != nil {
rel := models.PublicreportImageSlice{}
for _, r := range t.r.Images {
@ -232,6 +244,10 @@ func (o PublicreportPoolTemplate) BuildSetter() *models.PublicreportPoolSetter {
val := o.Status()
m.Status = omit.From(val)
}
if o.OrganizationID != nil {
val := o.OrganizationID()
m.OrganizationID = omitnull.FromNull(val)
}
return m
}
@ -344,6 +360,9 @@ func (o PublicreportPoolTemplate) Build() *models.PublicreportPool {
if o.Status != nil {
m.Status = o.Status()
}
if o.OrganizationID != nil {
m.OrganizationID = o.OrganizationID()
}
o.setModelRels(m)
@ -480,6 +499,25 @@ func ensureCreatablePublicreportPool(m *models.PublicreportPoolSetter) {
func (o *PublicreportPoolTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.PublicreportPool) error {
var err error
isOrganizationDone, _ := publicreportPoolRelOrganizationCtx.Value(ctx)
if !isOrganizationDone && o.r.Organization != nil {
ctx = publicreportPoolRelOrganizationCtx.WithValue(ctx, true)
if o.r.Organization.o.alreadyPersisted {
m.R.Organization = o.r.Organization.o.Build()
} else {
var rel0 *models.Organization
rel0, err = o.r.Organization.o.Create(ctx, exec)
if err != nil {
return err
}
err = m.AttachOrganization(ctx, exec, rel0)
if err != nil {
return err
}
}
}
isImagesDone, _ := publicreportPoolRelImagesCtx.Value(ctx)
if !isImagesDone && o.r.Images != nil {
ctx = publicreportPoolRelImagesCtx.WithValue(ctx, true)
@ -487,12 +525,12 @@ func (o *PublicreportPoolTemplate) insertOptRels(ctx context.Context, exec bob.E
if r.o.alreadyPersisted {
m.R.Images = append(m.R.Images, r.o.Build())
} else {
rel0, err := r.o.CreateMany(ctx, exec, r.number)
rel1, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachImages(ctx, exec, rel0...)
err = m.AttachImages(ctx, exec, rel1...)
if err != nil {
return err
}
@ -622,6 +660,7 @@ func (m publicreportPoolMods) RandomizeAllColumns(f *faker.Faker) PublicreportPo
PublicreportPoolMods.RandomReporterPhone(f),
PublicreportPoolMods.RandomSubscribe(f),
PublicreportPoolMods.RandomStatus(f),
PublicreportPoolMods.RandomOrganizationID(f),
}
}
@ -1599,12 +1638,100 @@ func (m publicreportPoolMods) RandomStatus(f *faker.Faker) PublicreportPoolMod {
})
}
// Set the model columns to this value
func (m publicreportPoolMods) OrganizationID(val null.Val[int32]) PublicreportPoolMod {
return PublicreportPoolModFunc(func(_ context.Context, o *PublicreportPoolTemplate) {
o.OrganizationID = func() null.Val[int32] { return val }
})
}
// Set the Column from the function
func (m publicreportPoolMods) OrganizationIDFunc(f func() null.Val[int32]) PublicreportPoolMod {
return PublicreportPoolModFunc(func(_ context.Context, o *PublicreportPoolTemplate) {
o.OrganizationID = f
})
}
// Clear any values for the column
func (m publicreportPoolMods) UnsetOrganizationID() PublicreportPoolMod {
return PublicreportPoolModFunc(func(_ context.Context, o *PublicreportPoolTemplate) {
o.OrganizationID = 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 publicreportPoolMods) RandomOrganizationID(f *faker.Faker) PublicreportPoolMod {
return PublicreportPoolModFunc(func(_ context.Context, o *PublicreportPoolTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(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 publicreportPoolMods) RandomOrganizationIDNotNull(f *faker.Faker) PublicreportPoolMod {
return PublicreportPoolModFunc(func(_ context.Context, o *PublicreportPoolTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(f)
return null.From(val)
}
})
}
func (m publicreportPoolMods) WithParentsCascading() PublicreportPoolMod {
return PublicreportPoolModFunc(func(ctx context.Context, o *PublicreportPoolTemplate) {
if isDone, _ := publicreportPoolWithParentsCascadingCtx.Value(ctx); isDone {
return
}
ctx = publicreportPoolWithParentsCascadingCtx.WithValue(ctx, true)
{
related := o.f.NewOrganizationWithContext(ctx, OrganizationMods.WithParentsCascading())
m.WithOrganization(related).Apply(ctx, o)
}
})
}
func (m publicreportPoolMods) WithOrganization(rel *OrganizationTemplate) PublicreportPoolMod {
return PublicreportPoolModFunc(func(ctx context.Context, o *PublicreportPoolTemplate) {
o.r.Organization = &publicreportPoolROrganizationR{
o: rel,
}
})
}
func (m publicreportPoolMods) WithNewOrganization(mods ...OrganizationMod) PublicreportPoolMod {
return PublicreportPoolModFunc(func(ctx context.Context, o *PublicreportPoolTemplate) {
related := o.f.NewOrganizationWithContext(ctx, mods...)
m.WithOrganization(related).Apply(ctx, o)
})
}
func (m publicreportPoolMods) WithExistingOrganization(em *models.Organization) PublicreportPoolMod {
return PublicreportPoolModFunc(func(ctx context.Context, o *PublicreportPoolTemplate) {
o.r.Organization = &publicreportPoolROrganizationR{
o: o.f.FromExistingOrganization(em),
}
})
}
func (m publicreportPoolMods) WithoutOrganization() PublicreportPoolMod {
return PublicreportPoolModFunc(func(ctx context.Context, o *PublicreportPoolTemplate) {
o.r.Organization = nil
})
}

View file

@ -48,6 +48,7 @@ type PublicreportQuickTemplate struct {
ReporterPhone func() string
Address func() string
Status func() enums.PublicreportReportstatustype
OrganizationID func() null.Val[int32]
r publicreportQuickR
f *Factory
@ -56,9 +57,13 @@ type PublicreportQuickTemplate struct {
}
type publicreportQuickR struct {
Organization *publicreportQuickROrganizationR
Images []*publicreportQuickRImagesR
}
type publicreportQuickROrganizationR struct {
o *OrganizationTemplate
}
type publicreportQuickRImagesR struct {
number int
o *PublicreportImageTemplate
@ -74,6 +79,13 @@ func (o *PublicreportQuickTemplate) Apply(ctx context.Context, mods ...Publicrep
// setModelRels creates and sets the relationships on *models.PublicreportQuick
// according to the relationships in the template. Nothing is inserted into the db
func (t PublicreportQuickTemplate) setModelRels(o *models.PublicreportQuick) {
if t.r.Organization != nil {
rel := t.r.Organization.o.Build()
rel.R.Quicks = append(rel.R.Quicks, o)
o.OrganizationID = null.From(rel.ID) // h2
o.R.Organization = rel
}
if t.r.Images != nil {
rel := models.PublicreportImageSlice{}
for _, r := range t.r.Images {
@ -132,6 +144,10 @@ func (o PublicreportQuickTemplate) BuildSetter() *models.PublicreportQuickSetter
val := o.Status()
m.Status = omit.From(val)
}
if o.OrganizationID != nil {
val := o.OrganizationID()
m.OrganizationID = omitnull.FromNull(val)
}
return m
}
@ -184,6 +200,9 @@ func (o PublicreportQuickTemplate) Build() *models.PublicreportQuick {
if o.Status != nil {
m.Status = o.Status()
}
if o.OrganizationID != nil {
m.OrganizationID = o.OrganizationID()
}
o.setModelRels(m)
@ -240,6 +259,25 @@ func ensureCreatablePublicreportQuick(m *models.PublicreportQuickSetter) {
func (o *PublicreportQuickTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.PublicreportQuick) error {
var err error
isOrganizationDone, _ := publicreportQuickRelOrganizationCtx.Value(ctx)
if !isOrganizationDone && o.r.Organization != nil {
ctx = publicreportQuickRelOrganizationCtx.WithValue(ctx, true)
if o.r.Organization.o.alreadyPersisted {
m.R.Organization = o.r.Organization.o.Build()
} else {
var rel0 *models.Organization
rel0, err = o.r.Organization.o.Create(ctx, exec)
if err != nil {
return err
}
err = m.AttachOrganization(ctx, exec, rel0)
if err != nil {
return err
}
}
}
isImagesDone, _ := publicreportQuickRelImagesCtx.Value(ctx)
if !isImagesDone && o.r.Images != nil {
ctx = publicreportQuickRelImagesCtx.WithValue(ctx, true)
@ -247,12 +285,12 @@ func (o *PublicreportQuickTemplate) insertOptRels(ctx context.Context, exec bob.
if r.o.alreadyPersisted {
m.R.Images = append(m.R.Images, r.o.Build())
} else {
rel0, err := r.o.CreateMany(ctx, exec, r.number)
rel1, err := r.o.CreateMany(ctx, exec, r.number)
if err != nil {
return err
}
err = m.AttachImages(ctx, exec, rel0...)
err = m.AttachImages(ctx, exec, rel1...)
if err != nil {
return err
}
@ -362,6 +400,7 @@ func (m publicreportQuickMods) RandomizeAllColumns(f *faker.Faker) PublicreportQ
PublicreportQuickMods.RandomReporterPhone(f),
PublicreportQuickMods.RandomAddress(f),
PublicreportQuickMods.RandomStatus(f),
PublicreportQuickMods.RandomOrganizationID(f),
}
}
@ -719,12 +758,100 @@ func (m publicreportQuickMods) RandomStatus(f *faker.Faker) PublicreportQuickMod
})
}
// Set the model columns to this value
func (m publicreportQuickMods) OrganizationID(val null.Val[int32]) PublicreportQuickMod {
return PublicreportQuickModFunc(func(_ context.Context, o *PublicreportQuickTemplate) {
o.OrganizationID = func() null.Val[int32] { return val }
})
}
// Set the Column from the function
func (m publicreportQuickMods) OrganizationIDFunc(f func() null.Val[int32]) PublicreportQuickMod {
return PublicreportQuickModFunc(func(_ context.Context, o *PublicreportQuickTemplate) {
o.OrganizationID = f
})
}
// Clear any values for the column
func (m publicreportQuickMods) UnsetOrganizationID() PublicreportQuickMod {
return PublicreportQuickModFunc(func(_ context.Context, o *PublicreportQuickTemplate) {
o.OrganizationID = 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 publicreportQuickMods) RandomOrganizationID(f *faker.Faker) PublicreportQuickMod {
return PublicreportQuickModFunc(func(_ context.Context, o *PublicreportQuickTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(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 publicreportQuickMods) RandomOrganizationIDNotNull(f *faker.Faker) PublicreportQuickMod {
return PublicreportQuickModFunc(func(_ context.Context, o *PublicreportQuickTemplate) {
o.OrganizationID = func() null.Val[int32] {
if f == nil {
f = &defaultFaker
}
val := random_int32(f)
return null.From(val)
}
})
}
func (m publicreportQuickMods) WithParentsCascading() PublicreportQuickMod {
return PublicreportQuickModFunc(func(ctx context.Context, o *PublicreportQuickTemplate) {
if isDone, _ := publicreportQuickWithParentsCascadingCtx.Value(ctx); isDone {
return
}
ctx = publicreportQuickWithParentsCascadingCtx.WithValue(ctx, true)
{
related := o.f.NewOrganizationWithContext(ctx, OrganizationMods.WithParentsCascading())
m.WithOrganization(related).Apply(ctx, o)
}
})
}
func (m publicreportQuickMods) WithOrganization(rel *OrganizationTemplate) PublicreportQuickMod {
return PublicreportQuickModFunc(func(ctx context.Context, o *PublicreportQuickTemplate) {
o.r.Organization = &publicreportQuickROrganizationR{
o: rel,
}
})
}
func (m publicreportQuickMods) WithNewOrganization(mods ...OrganizationMod) PublicreportQuickMod {
return PublicreportQuickModFunc(func(ctx context.Context, o *PublicreportQuickTemplate) {
related := o.f.NewOrganizationWithContext(ctx, mods...)
m.WithOrganization(related).Apply(ctx, o)
})
}
func (m publicreportQuickMods) WithExistingOrganization(em *models.Organization) PublicreportQuickMod {
return PublicreportQuickModFunc(func(ctx context.Context, o *PublicreportQuickTemplate) {
o.r.Organization = &publicreportQuickROrganizationR{
o: o.f.FromExistingOrganization(em),
}
})
}
func (m publicreportQuickMods) WithoutOrganization() PublicreportQuickMod {
return PublicreportQuickModFunc(func(ctx context.Context, o *PublicreportQuickTemplate) {
o.r.Organization = nil
})
}

View file

@ -0,0 +1,8 @@
-- +goose Up
ALTER TABLE publicreport.quick ADD COLUMN organization_id INTEGER REFERENCES "public"."organization"(id);
ALTER TABLE publicreport.pool ADD COLUMN organization_id INTEGER REFERENCES "public"."organization"(id);
ALTER TABLE publicreport.nuisance ADD COLUMN organization_id INTEGER REFERENCES "public"."organization"(id);
-- +goose Down
ALTER TABLE publicreport.nuisance DROP COLUMN organization_id;
ALTER TABLE publicreport.pool DROP COLUMN organization_id;
ALTER TABLE publicreport.quick DROP COLUMN organization_id;

View file

@ -0,0 +1,2 @@
-- +goose UP
ALTER TABLE public.organization ADD COLUMN logo_uuid UUID;

View file

@ -79,6 +79,7 @@ type joins[Q dialect.Joinable] struct {
Organizations joinSet[organizationJoins[Q]]
PublicreportImages joinSet[publicreportImageJoins[Q]]
PublicreportImageExifs joinSet[publicreportImageExifJoins[Q]]
PublicreportNuisances joinSet[publicreportNuisanceJoins[Q]]
PublicreportPools joinSet[publicreportPoolJoins[Q]]
PublicreportPoolImages joinSet[publicreportPoolImageJoins[Q]]
PublicreportQuicks joinSet[publicreportQuickJoins[Q]]
@ -143,6 +144,7 @@ func getJoins[Q dialect.Joinable]() joins[Q] {
Organizations: buildJoinSet[organizationJoins[Q]](Organizations.Columns, buildOrganizationJoins),
PublicreportImages: buildJoinSet[publicreportImageJoins[Q]](PublicreportImages.Columns, buildPublicreportImageJoins),
PublicreportImageExifs: buildJoinSet[publicreportImageExifJoins[Q]](PublicreportImageExifs.Columns, buildPublicreportImageExifJoins),
PublicreportNuisances: buildJoinSet[publicreportNuisanceJoins[Q]](PublicreportNuisances.Columns, buildPublicreportNuisanceJoins),
PublicreportPools: buildJoinSet[publicreportPoolJoins[Q]](PublicreportPools.Columns, buildPublicreportPoolJoins),
PublicreportPoolImages: buildJoinSet[publicreportPoolImageJoins[Q]](PublicreportPoolImages.Columns, buildPublicreportPoolImageJoins),
PublicreportQuicks: buildJoinSet[publicreportQuickJoins[Q]](PublicreportQuicks.Columns, buildPublicreportQuickJoins),

View file

@ -64,6 +64,7 @@ type preloaders struct {
Organization organizationPreloader
PublicreportImage publicreportImagePreloader
PublicreportImageExif publicreportImageExifPreloader
PublicreportNuisance publicreportNuisancePreloader
PublicreportPool publicreportPoolPreloader
PublicreportPoolImage publicreportPoolImagePreloader
PublicreportQuick publicreportQuickPreloader
@ -120,6 +121,7 @@ func getPreloaders() preloaders {
Organization: buildOrganizationPreloader(),
PublicreportImage: buildPublicreportImagePreloader(),
PublicreportImageExif: buildPublicreportImageExifPreloader(),
PublicreportNuisance: buildPublicreportNuisancePreloader(),
PublicreportPool: buildPublicreportPoolPreloader(),
PublicreportPoolImage: buildPublicreportPoolImagePreloader(),
PublicreportQuick: buildPublicreportQuickPreloader(),
@ -182,6 +184,7 @@ type thenLoaders[Q orm.Loadable] struct {
Organization organizationThenLoader[Q]
PublicreportImage publicreportImageThenLoader[Q]
PublicreportImageExif publicreportImageExifThenLoader[Q]
PublicreportNuisance publicreportNuisanceThenLoader[Q]
PublicreportPool publicreportPoolThenLoader[Q]
PublicreportPoolImage publicreportPoolImageThenLoader[Q]
PublicreportQuick publicreportQuickThenLoader[Q]
@ -238,6 +241,7 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] {
Organization: buildOrganizationThenLoader[Q](),
PublicreportImage: buildPublicreportImageThenLoader[Q](),
PublicreportImageExif: buildPublicreportImageExifThenLoader[Q](),
PublicreportNuisance: buildPublicreportNuisanceThenLoader[Q](),
PublicreportPool: buildPublicreportPoolThenLoader[Q](),
PublicreportPoolImage: buildPublicreportPoolImageThenLoader[Q](),
PublicreportQuick: buildPublicreportQuickThenLoader[Q](),

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@ package models
import (
"context"
"fmt"
"io"
"time"
@ -19,6 +20,9 @@ import (
"github.com/stephenafamo/bob/dialect/psql/sm"
"github.com/stephenafamo/bob/dialect/psql/um"
"github.com/stephenafamo/bob/expr"
"github.com/stephenafamo/bob/mods"
"github.com/stephenafamo/bob/orm"
"github.com/stephenafamo/bob/types/pgtypes"
)
// PublicreportNuisance is an object representing the database table.
@ -50,6 +54,9 @@ type PublicreportNuisance struct {
Address string `db:"address" `
Location null.Val[string] `db:"location" `
Status enums.PublicreportReportstatustype `db:"status" `
OrganizationID null.Val[int32] `db:"organization_id" `
R publicreportNuisanceR `db:"-" `
}
// PublicreportNuisanceSlice is an alias for a slice of pointers to PublicreportNuisance.
@ -62,10 +69,15 @@ var PublicreportNuisances = psql.NewTablex[*PublicreportNuisance, PublicreportNu
// PublicreportNuisancesQuery is a query on the nuisance table
type PublicreportNuisancesQuery = *psql.ViewQuery[*PublicreportNuisance, PublicreportNuisanceSlice]
// publicreportNuisanceR is where relationships are stored.
type publicreportNuisanceR struct {
Organization *Organization // publicreport.nuisance.nuisance_organization_id_fkey
}
func buildPublicreportNuisanceColumns(alias string) publicreportNuisanceColumns {
return publicreportNuisanceColumns{
ColumnsExpr: expr.NewColumnsExpr(
"id", "additional_info", "created", "duration", "email", "inspection_type", "source_location", "preferred_date_range", "preferred_time", "request_call", "severity", "source_container", "source_description", "source_roof", "source_stagnant", "time_of_day_day", "time_of_day_early", "time_of_day_evening", "time_of_day_night", "public_id", "reporter_address", "reporter_email", "reporter_name", "reporter_phone", "address", "location", "status",
"id", "additional_info", "created", "duration", "email", "inspection_type", "source_location", "preferred_date_range", "preferred_time", "request_call", "severity", "source_container", "source_description", "source_roof", "source_stagnant", "time_of_day_day", "time_of_day_early", "time_of_day_evening", "time_of_day_night", "public_id", "reporter_address", "reporter_email", "reporter_name", "reporter_phone", "address", "location", "status", "organization_id",
).WithParent("publicreport.nuisance"),
tableAlias: alias,
ID: psql.Quote(alias, "id"),
@ -95,6 +107,7 @@ func buildPublicreportNuisanceColumns(alias string) publicreportNuisanceColumns
Address: psql.Quote(alias, "address"),
Location: psql.Quote(alias, "location"),
Status: psql.Quote(alias, "status"),
OrganizationID: psql.Quote(alias, "organization_id"),
}
}
@ -128,6 +141,7 @@ type publicreportNuisanceColumns struct {
Address psql.Expression
Location psql.Expression
Status psql.Expression
OrganizationID psql.Expression
}
func (c publicreportNuisanceColumns) Alias() string {
@ -169,10 +183,11 @@ type PublicreportNuisanceSetter struct {
Address omit.Val[string] `db:"address" `
Location omitnull.Val[string] `db:"location" `
Status omit.Val[enums.PublicreportReportstatustype] `db:"status" `
OrganizationID omitnull.Val[int32] `db:"organization_id" `
}
func (s PublicreportNuisanceSetter) SetColumns() []string {
vals := make([]string, 0, 27)
vals := make([]string, 0, 28)
if s.ID.IsValue() {
vals = append(vals, "id")
}
@ -254,6 +269,9 @@ func (s PublicreportNuisanceSetter) SetColumns() []string {
if s.Status.IsValue() {
vals = append(vals, "status")
}
if !s.OrganizationID.IsUnset() {
vals = append(vals, "organization_id")
}
return vals
}
@ -339,6 +357,9 @@ func (s PublicreportNuisanceSetter) Overwrite(t *PublicreportNuisance) {
if s.Status.IsValue() {
t.Status = s.Status.MustGet()
}
if !s.OrganizationID.IsUnset() {
t.OrganizationID = s.OrganizationID.MustGetNull()
}
}
func (s *PublicreportNuisanceSetter) Apply(q *dialect.InsertQuery) {
@ -347,7 +368,7 @@ func (s *PublicreportNuisanceSetter) Apply(q *dialect.InsertQuery) {
})
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
vals := make([]bob.Expression, 27)
vals := make([]bob.Expression, 28)
if s.ID.IsValue() {
vals[0] = psql.Arg(s.ID.MustGet())
} else {
@ -510,6 +531,12 @@ func (s *PublicreportNuisanceSetter) Apply(q *dialect.InsertQuery) {
vals[26] = psql.Raw("DEFAULT")
}
if !s.OrganizationID.IsUnset() {
vals[27] = psql.Arg(s.OrganizationID.MustGetNull())
} else {
vals[27] = psql.Raw("DEFAULT")
}
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
}))
}
@ -519,7 +546,7 @@ func (s PublicreportNuisanceSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
}
func (s PublicreportNuisanceSetter) Expressions(prefix ...string) []bob.Expression {
exprs := make([]bob.Expression, 0, 27)
exprs := make([]bob.Expression, 0, 28)
if s.ID.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
@ -710,6 +737,13 @@ func (s PublicreportNuisanceSetter) Expressions(prefix ...string) []bob.Expressi
}})
}
if !s.OrganizationID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "organization_id")...),
psql.Arg(s.OrganizationID),
}})
}
return exprs
}
@ -771,6 +805,7 @@ func (o *PublicreportNuisance) Update(ctx context.Context, exec bob.Executor, s
return err
}
o.R = v.R
*o = *v
return nil
@ -790,7 +825,7 @@ func (o *PublicreportNuisance) Reload(ctx context.Context, exec bob.Executor) er
if err != nil {
return err
}
o2.R = o.R
*o = *o2
return nil
@ -837,7 +872,7 @@ func (o PublicreportNuisanceSlice) copyMatchingRows(from ...*PublicreportNuisanc
if new.ID != old.ID {
continue
}
new.R = old.R
o[i] = new
break
}
@ -935,6 +970,78 @@ func (o PublicreportNuisanceSlice) ReloadAll(ctx context.Context, exec bob.Execu
return nil
}
// Organization starts a query for related objects on organization
func (o *PublicreportNuisance) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
return Organizations.Query(append(mods,
sm.Where(Organizations.Columns.ID.EQ(psql.Arg(o.OrganizationID))),
)...)
}
func (os PublicreportNuisanceSlice) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
pkOrganizationID := make(pgtypes.Array[null.Val[int32]], 0, len(os))
for _, o := range os {
if o == nil {
continue
}
pkOrganizationID = append(pkOrganizationID, o.OrganizationID)
}
PKArgExpr := psql.Select(sm.Columns(
psql.F("unnest", psql.Cast(psql.Arg(pkOrganizationID), "integer[]")),
))
return Organizations.Query(append(mods,
sm.Where(psql.Group(Organizations.Columns.ID).OP("IN", PKArgExpr)),
)...)
}
func attachPublicreportNuisanceOrganization0(ctx context.Context, exec bob.Executor, count int, publicreportNuisance0 *PublicreportNuisance, organization1 *Organization) (*PublicreportNuisance, error) {
setter := &PublicreportNuisanceSetter{
OrganizationID: omitnull.From(organization1.ID),
}
err := publicreportNuisance0.Update(ctx, exec, setter)
if err != nil {
return nil, fmt.Errorf("attachPublicreportNuisanceOrganization0: %w", err)
}
return publicreportNuisance0, nil
}
func (publicreportNuisance0 *PublicreportNuisance) InsertOrganization(ctx context.Context, exec bob.Executor, related *OrganizationSetter) error {
var err error
organization1, err := Organizations.Insert(related).One(ctx, exec)
if err != nil {
return fmt.Errorf("inserting related objects: %w", err)
}
_, err = attachPublicreportNuisanceOrganization0(ctx, exec, 1, publicreportNuisance0, organization1)
if err != nil {
return err
}
publicreportNuisance0.R.Organization = organization1
organization1.R.Nuisances = append(organization1.R.Nuisances, publicreportNuisance0)
return nil
}
func (publicreportNuisance0 *PublicreportNuisance) AttachOrganization(ctx context.Context, exec bob.Executor, organization1 *Organization) error {
var err error
_, err = attachPublicreportNuisanceOrganization0(ctx, exec, 1, publicreportNuisance0, organization1)
if err != nil {
return err
}
publicreportNuisance0.R.Organization = organization1
organization1.R.Nuisances = append(organization1.R.Nuisances, publicreportNuisance0)
return nil
}
type publicreportNuisanceWhere[Q psql.Filterable] struct {
ID psql.WhereMod[Q, int32]
AdditionalInfo psql.WhereMod[Q, string]
@ -963,6 +1070,7 @@ type publicreportNuisanceWhere[Q psql.Filterable] struct {
Address psql.WhereMod[Q, string]
Location psql.WhereNullMod[Q, string]
Status psql.WhereMod[Q, enums.PublicreportReportstatustype]
OrganizationID psql.WhereNullMod[Q, int32]
}
func (publicreportNuisanceWhere[Q]) AliasedAs(alias string) publicreportNuisanceWhere[Q] {
@ -998,5 +1106,154 @@ func buildPublicreportNuisanceWhere[Q psql.Filterable](cols publicreportNuisance
Address: psql.Where[Q, string](cols.Address),
Location: psql.WhereNull[Q, string](cols.Location),
Status: psql.Where[Q, enums.PublicreportReportstatustype](cols.Status),
OrganizationID: psql.WhereNull[Q, int32](cols.OrganizationID),
}
}
func (o *PublicreportNuisance) Preload(name string, retrieved any) error {
if o == nil {
return nil
}
switch name {
case "Organization":
rel, ok := retrieved.(*Organization)
if !ok {
return fmt.Errorf("publicreportNuisance cannot load %T as %q", retrieved, name)
}
o.R.Organization = rel
if rel != nil {
rel.R.Nuisances = PublicreportNuisanceSlice{o}
}
return nil
default:
return fmt.Errorf("publicreportNuisance has no relationship %q", name)
}
}
type publicreportNuisancePreloader struct {
Organization func(...psql.PreloadOption) psql.Preloader
}
func buildPublicreportNuisancePreloader() publicreportNuisancePreloader {
return publicreportNuisancePreloader{
Organization: func(opts ...psql.PreloadOption) psql.Preloader {
return psql.Preload[*Organization, OrganizationSlice](psql.PreloadRel{
Name: "Organization",
Sides: []psql.PreloadSide{
{
From: PublicreportNuisances,
To: Organizations,
FromColumns: []string{"organization_id"},
ToColumns: []string{"id"},
},
},
}, Organizations.Columns.Names(), opts...)
},
}
}
type publicreportNuisanceThenLoader[Q orm.Loadable] struct {
Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
}
func buildPublicreportNuisanceThenLoader[Q orm.Loadable]() publicreportNuisanceThenLoader[Q] {
type OrganizationLoadInterface interface {
LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
}
return publicreportNuisanceThenLoader[Q]{
Organization: thenLoadBuilder[Q](
"Organization",
func(ctx context.Context, exec bob.Executor, retrieved OrganizationLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
return retrieved.LoadOrganization(ctx, exec, mods...)
},
),
}
}
// LoadOrganization loads the publicreportNuisance's Organization into the .R struct
func (o *PublicreportNuisance) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if o == nil {
return nil
}
// Reset the relationship
o.R.Organization = nil
related, err := o.Organization(mods...).One(ctx, exec)
if err != nil {
return err
}
related.R.Nuisances = PublicreportNuisanceSlice{o}
o.R.Organization = related
return nil
}
// LoadOrganization loads the publicreportNuisance's Organization into the .R struct
func (os PublicreportNuisanceSlice) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if len(os) == 0 {
return nil
}
organizations, err := os.Organization(mods...).All(ctx, exec)
if err != nil {
return err
}
for _, o := range os {
if o == nil {
continue
}
for _, rel := range organizations {
if !o.OrganizationID.IsValue() {
continue
}
if !(o.OrganizationID.IsValue() && o.OrganizationID.MustGet() == rel.ID) {
continue
}
rel.R.Nuisances = append(rel.R.Nuisances, o)
o.R.Organization = rel
break
}
}
return nil
}
type publicreportNuisanceJoins[Q dialect.Joinable] struct {
typ string
Organization modAs[Q, organizationColumns]
}
func (j publicreportNuisanceJoins[Q]) aliasedAs(alias string) publicreportNuisanceJoins[Q] {
return buildPublicreportNuisanceJoins[Q](buildPublicreportNuisanceColumns(alias), j.typ)
}
func buildPublicreportNuisanceJoins[Q dialect.Joinable](cols publicreportNuisanceColumns, typ string) publicreportNuisanceJoins[Q] {
return publicreportNuisanceJoins[Q]{
typ: typ,
Organization: modAs[Q, organizationColumns]{
c: Organizations.Columns,
f: func(to organizationColumns) bob.Mod[Q] {
mods := make(mods.QueryMods[Q], 0, 1)
{
mods = append(mods, dialect.Join[Q](typ, Organizations.Name().As(to.Alias())).On(
to.ID.EQ(cols.OrganizationID),
))
}
return mods
},
},
}
}

View file

@ -59,6 +59,7 @@ type PublicreportPool struct {
ReporterPhone string `db:"reporter_phone" `
Subscribe bool `db:"subscribe" `
Status enums.PublicreportReportstatustype `db:"status" `
OrganizationID null.Val[int32] `db:"organization_id" `
R publicreportPoolR `db:"-" `
@ -77,13 +78,14 @@ type PublicreportPoolsQuery = *psql.ViewQuery[*PublicreportPool, PublicreportPoo
// publicreportPoolR is where relationships are stored.
type publicreportPoolR struct {
Organization *Organization // publicreport.pool.pool_organization_id_fkey
Images PublicreportImageSlice // publicreport.pool_image.pool_image_image_id_fkeypublicreport.pool_image.pool_image_pool_id_fkey
}
func buildPublicreportPoolColumns(alias string) publicreportPoolColumns {
return publicreportPoolColumns{
ColumnsExpr: expr.NewColumnsExpr(
"id", "access_comments", "access_gate", "access_fence", "access_locked", "access_dog", "access_other", "address", "address_country", "address_post_code", "address_place", "address_street", "address_region", "comments", "created", "h3cell", "has_adult", "has_larvae", "has_pupae", "location", "map_zoom", "owner_email", "owner_name", "owner_phone", "public_id", "reporter_email", "reporter_name", "reporter_phone", "subscribe", "status",
"id", "access_comments", "access_gate", "access_fence", "access_locked", "access_dog", "access_other", "address", "address_country", "address_post_code", "address_place", "address_street", "address_region", "comments", "created", "h3cell", "has_adult", "has_larvae", "has_pupae", "location", "map_zoom", "owner_email", "owner_name", "owner_phone", "public_id", "reporter_email", "reporter_name", "reporter_phone", "subscribe", "status", "organization_id",
).WithParent("publicreport.pool"),
tableAlias: alias,
ID: psql.Quote(alias, "id"),
@ -116,6 +118,7 @@ func buildPublicreportPoolColumns(alias string) publicreportPoolColumns {
ReporterPhone: psql.Quote(alias, "reporter_phone"),
Subscribe: psql.Quote(alias, "subscribe"),
Status: psql.Quote(alias, "status"),
OrganizationID: psql.Quote(alias, "organization_id"),
}
}
@ -152,6 +155,7 @@ type publicreportPoolColumns struct {
ReporterPhone psql.Expression
Subscribe psql.Expression
Status psql.Expression
OrganizationID psql.Expression
}
func (c publicreportPoolColumns) Alias() string {
@ -196,10 +200,11 @@ type PublicreportPoolSetter struct {
ReporterPhone omit.Val[string] `db:"reporter_phone" `
Subscribe omit.Val[bool] `db:"subscribe" `
Status omit.Val[enums.PublicreportReportstatustype] `db:"status" `
OrganizationID omitnull.Val[int32] `db:"organization_id" `
}
func (s PublicreportPoolSetter) SetColumns() []string {
vals := make([]string, 0, 30)
vals := make([]string, 0, 31)
if s.ID.IsValue() {
vals = append(vals, "id")
}
@ -290,6 +295,9 @@ func (s PublicreportPoolSetter) SetColumns() []string {
if s.Status.IsValue() {
vals = append(vals, "status")
}
if !s.OrganizationID.IsUnset() {
vals = append(vals, "organization_id")
}
return vals
}
@ -384,6 +392,9 @@ func (s PublicreportPoolSetter) Overwrite(t *PublicreportPool) {
if s.Status.IsValue() {
t.Status = s.Status.MustGet()
}
if !s.OrganizationID.IsUnset() {
t.OrganizationID = s.OrganizationID.MustGetNull()
}
}
func (s *PublicreportPoolSetter) Apply(q *dialect.InsertQuery) {
@ -392,7 +403,7 @@ func (s *PublicreportPoolSetter) Apply(q *dialect.InsertQuery) {
})
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
vals := make([]bob.Expression, 30)
vals := make([]bob.Expression, 31)
if s.ID.IsValue() {
vals[0] = psql.Arg(s.ID.MustGet())
} else {
@ -573,6 +584,12 @@ func (s *PublicreportPoolSetter) Apply(q *dialect.InsertQuery) {
vals[29] = psql.Raw("DEFAULT")
}
if !s.OrganizationID.IsUnset() {
vals[30] = psql.Arg(s.OrganizationID.MustGetNull())
} else {
vals[30] = psql.Raw("DEFAULT")
}
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
}))
}
@ -582,7 +599,7 @@ func (s PublicreportPoolSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
}
func (s PublicreportPoolSetter) Expressions(prefix ...string) []bob.Expression {
exprs := make([]bob.Expression, 0, 30)
exprs := make([]bob.Expression, 0, 31)
if s.ID.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
@ -794,6 +811,13 @@ func (s PublicreportPoolSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if !s.OrganizationID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "organization_id")...),
psql.Arg(s.OrganizationID),
}})
}
return exprs
}
@ -1020,6 +1044,30 @@ func (o PublicreportPoolSlice) ReloadAll(ctx context.Context, exec bob.Executor)
return nil
}
// Organization starts a query for related objects on organization
func (o *PublicreportPool) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
return Organizations.Query(append(mods,
sm.Where(Organizations.Columns.ID.EQ(psql.Arg(o.OrganizationID))),
)...)
}
func (os PublicreportPoolSlice) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
pkOrganizationID := make(pgtypes.Array[null.Val[int32]], 0, len(os))
for _, o := range os {
if o == nil {
continue
}
pkOrganizationID = append(pkOrganizationID, o.OrganizationID)
}
PKArgExpr := psql.Select(sm.Columns(
psql.F("unnest", psql.Cast(psql.Arg(pkOrganizationID), "integer[]")),
))
return Organizations.Query(append(mods,
sm.Where(psql.Group(Organizations.Columns.ID).OP("IN", PKArgExpr)),
)...)
}
// Images starts a query for related objects on publicreport.image
func (o *PublicreportPool) Images(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportImagesQuery {
return PublicreportImages.Query(append(mods,
@ -1049,6 +1097,54 @@ func (os PublicreportPoolSlice) Images(mods ...bob.Mod[*dialect.SelectQuery]) Pu
)...)
}
func attachPublicreportPoolOrganization0(ctx context.Context, exec bob.Executor, count int, publicreportPool0 *PublicreportPool, organization1 *Organization) (*PublicreportPool, error) {
setter := &PublicreportPoolSetter{
OrganizationID: omitnull.From(organization1.ID),
}
err := publicreportPool0.Update(ctx, exec, setter)
if err != nil {
return nil, fmt.Errorf("attachPublicreportPoolOrganization0: %w", err)
}
return publicreportPool0, nil
}
func (publicreportPool0 *PublicreportPool) InsertOrganization(ctx context.Context, exec bob.Executor, related *OrganizationSetter) error {
var err error
organization1, err := Organizations.Insert(related).One(ctx, exec)
if err != nil {
return fmt.Errorf("inserting related objects: %w", err)
}
_, err = attachPublicreportPoolOrganization0(ctx, exec, 1, publicreportPool0, organization1)
if err != nil {
return err
}
publicreportPool0.R.Organization = organization1
organization1.R.PublicreportPool = append(organization1.R.PublicreportPool, publicreportPool0)
return nil
}
func (publicreportPool0 *PublicreportPool) AttachOrganization(ctx context.Context, exec bob.Executor, organization1 *Organization) error {
var err error
_, err = attachPublicreportPoolOrganization0(ctx, exec, 1, publicreportPool0, organization1)
if err != nil {
return err
}
publicreportPool0.R.Organization = organization1
organization1.R.PublicreportPool = append(organization1.R.PublicreportPool, publicreportPool0)
return nil
}
func attachPublicreportPoolImages0(ctx context.Context, exec bob.Executor, count int, publicreportPool0 *PublicreportPool, publicreportImages2 PublicreportImageSlice) (PublicreportPoolImageSlice, error) {
setters := make([]*PublicreportPoolImageSetter, count)
for i := range count {
@ -1145,6 +1241,7 @@ type publicreportPoolWhere[Q psql.Filterable] struct {
ReporterPhone psql.WhereMod[Q, string]
Subscribe psql.WhereMod[Q, bool]
Status psql.WhereMod[Q, enums.PublicreportReportstatustype]
OrganizationID psql.WhereNullMod[Q, int32]
}
func (publicreportPoolWhere[Q]) AliasedAs(alias string) publicreportPoolWhere[Q] {
@ -1183,6 +1280,7 @@ func buildPublicreportPoolWhere[Q psql.Filterable](cols publicreportPoolColumns)
ReporterPhone: psql.Where[Q, string](cols.ReporterPhone),
Subscribe: psql.Where[Q, bool](cols.Subscribe),
Status: psql.Where[Q, enums.PublicreportReportstatustype](cols.Status),
OrganizationID: psql.WhereNull[Q, int32](cols.OrganizationID),
}
}
@ -1192,6 +1290,18 @@ func (o *PublicreportPool) Preload(name string, retrieved any) error {
}
switch name {
case "Organization":
rel, ok := retrieved.(*Organization)
if !ok {
return fmt.Errorf("publicreportPool cannot load %T as %q", retrieved, name)
}
o.R.Organization = rel
if rel != nil {
rel.R.PublicreportPool = PublicreportPoolSlice{o}
}
return nil
case "Images":
rels, ok := retrieved.(PublicreportImageSlice)
if !ok {
@ -1211,22 +1321,48 @@ func (o *PublicreportPool) Preload(name string, retrieved any) error {
}
}
type publicreportPoolPreloader struct{}
type publicreportPoolPreloader struct {
Organization func(...psql.PreloadOption) psql.Preloader
}
func buildPublicreportPoolPreloader() publicreportPoolPreloader {
return publicreportPoolPreloader{}
return publicreportPoolPreloader{
Organization: func(opts ...psql.PreloadOption) psql.Preloader {
return psql.Preload[*Organization, OrganizationSlice](psql.PreloadRel{
Name: "Organization",
Sides: []psql.PreloadSide{
{
From: PublicreportPools,
To: Organizations,
FromColumns: []string{"organization_id"},
ToColumns: []string{"id"},
},
},
}, Organizations.Columns.Names(), opts...)
},
}
}
type publicreportPoolThenLoader[Q orm.Loadable] struct {
Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
Images func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
}
func buildPublicreportPoolThenLoader[Q orm.Loadable]() publicreportPoolThenLoader[Q] {
type OrganizationLoadInterface interface {
LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
}
type ImagesLoadInterface interface {
LoadImages(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
}
return publicreportPoolThenLoader[Q]{
Organization: thenLoadBuilder[Q](
"Organization",
func(ctx context.Context, exec bob.Executor, retrieved OrganizationLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
return retrieved.LoadOrganization(ctx, exec, mods...)
},
),
Images: thenLoadBuilder[Q](
"Images",
func(ctx context.Context, exec bob.Executor, retrieved ImagesLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
@ -1236,6 +1372,61 @@ func buildPublicreportPoolThenLoader[Q orm.Loadable]() publicreportPoolThenLoade
}
}
// LoadOrganization loads the publicreportPool's Organization into the .R struct
func (o *PublicreportPool) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if o == nil {
return nil
}
// Reset the relationship
o.R.Organization = nil
related, err := o.Organization(mods...).One(ctx, exec)
if err != nil {
return err
}
related.R.PublicreportPool = PublicreportPoolSlice{o}
o.R.Organization = related
return nil
}
// LoadOrganization loads the publicreportPool's Organization into the .R struct
func (os PublicreportPoolSlice) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if len(os) == 0 {
return nil
}
organizations, err := os.Organization(mods...).All(ctx, exec)
if err != nil {
return err
}
for _, o := range os {
if o == nil {
continue
}
for _, rel := range organizations {
if !o.OrganizationID.IsValue() {
continue
}
if !(o.OrganizationID.IsValue() && o.OrganizationID.MustGet() == rel.ID) {
continue
}
rel.R.PublicreportPool = append(rel.R.PublicreportPool, o)
o.R.Organization = rel
break
}
}
return nil
}
// LoadImages loads the publicreportPool's Images into the .R struct
func (o *PublicreportPool) LoadImages(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if o == nil {
@ -1415,6 +1606,7 @@ func (os PublicreportPoolSlice) LoadCountImages(ctx context.Context, exec bob.Ex
type publicreportPoolJoins[Q dialect.Joinable] struct {
typ string
Organization modAs[Q, organizationColumns]
Images modAs[Q, publicreportImageColumns]
}
@ -1425,6 +1617,20 @@ func (j publicreportPoolJoins[Q]) aliasedAs(alias string) publicreportPoolJoins[
func buildPublicreportPoolJoins[Q dialect.Joinable](cols publicreportPoolColumns, typ string) publicreportPoolJoins[Q] {
return publicreportPoolJoins[Q]{
typ: typ,
Organization: modAs[Q, organizationColumns]{
c: Organizations.Columns,
f: func(to organizationColumns) bob.Mod[Q] {
mods := make(mods.QueryMods[Q], 0, 1)
{
mods = append(mods, dialect.Join[Q](typ, Organizations.Name().As(to.Alias())).On(
to.ID.EQ(cols.OrganizationID),
))
}
return mods
},
},
Images: modAs[Q, publicreportImageColumns]{
c: PublicreportImages.Columns,
f: func(to publicreportImageColumns) bob.Mod[Q] {

View file

@ -39,6 +39,7 @@ type PublicreportQuick struct {
ReporterPhone string `db:"reporter_phone" `
Address string `db:"address" `
Status enums.PublicreportReportstatustype `db:"status" `
OrganizationID null.Val[int32] `db:"organization_id" `
R publicreportQuickR `db:"-" `
@ -57,13 +58,14 @@ type PublicreportQuicksQuery = *psql.ViewQuery[*PublicreportQuick, PublicreportQ
// publicreportQuickR is where relationships are stored.
type publicreportQuickR struct {
Organization *Organization // publicreport.quick.quick_organization_id_fkey
Images PublicreportImageSlice // publicreport.quick_image.quick_image_image_id_fkeypublicreport.quick_image.quick_image_quick_id_fkey
}
func buildPublicreportQuickColumns(alias string) publicreportQuickColumns {
return publicreportQuickColumns{
ColumnsExpr: expr.NewColumnsExpr(
"id", "created", "comments", "location", "h3cell", "public_id", "reporter_email", "reporter_phone", "address", "status",
"id", "created", "comments", "location", "h3cell", "public_id", "reporter_email", "reporter_phone", "address", "status", "organization_id",
).WithParent("publicreport.quick"),
tableAlias: alias,
ID: psql.Quote(alias, "id"),
@ -76,6 +78,7 @@ func buildPublicreportQuickColumns(alias string) publicreportQuickColumns {
ReporterPhone: psql.Quote(alias, "reporter_phone"),
Address: psql.Quote(alias, "address"),
Status: psql.Quote(alias, "status"),
OrganizationID: psql.Quote(alias, "organization_id"),
}
}
@ -92,6 +95,7 @@ type publicreportQuickColumns struct {
ReporterPhone psql.Expression
Address psql.Expression
Status psql.Expression
OrganizationID psql.Expression
}
func (c publicreportQuickColumns) Alias() string {
@ -116,10 +120,11 @@ type PublicreportQuickSetter struct {
ReporterPhone omit.Val[string] `db:"reporter_phone" `
Address omit.Val[string] `db:"address" `
Status omit.Val[enums.PublicreportReportstatustype] `db:"status" `
OrganizationID omitnull.Val[int32] `db:"organization_id" `
}
func (s PublicreportQuickSetter) SetColumns() []string {
vals := make([]string, 0, 10)
vals := make([]string, 0, 11)
if s.ID.IsValue() {
vals = append(vals, "id")
}
@ -150,6 +155,9 @@ func (s PublicreportQuickSetter) SetColumns() []string {
if s.Status.IsValue() {
vals = append(vals, "status")
}
if !s.OrganizationID.IsUnset() {
vals = append(vals, "organization_id")
}
return vals
}
@ -184,6 +192,9 @@ func (s PublicreportQuickSetter) Overwrite(t *PublicreportQuick) {
if s.Status.IsValue() {
t.Status = s.Status.MustGet()
}
if !s.OrganizationID.IsUnset() {
t.OrganizationID = s.OrganizationID.MustGetNull()
}
}
func (s *PublicreportQuickSetter) Apply(q *dialect.InsertQuery) {
@ -192,7 +203,7 @@ func (s *PublicreportQuickSetter) Apply(q *dialect.InsertQuery) {
})
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
vals := make([]bob.Expression, 10)
vals := make([]bob.Expression, 11)
if s.ID.IsValue() {
vals[0] = psql.Arg(s.ID.MustGet())
} else {
@ -253,6 +264,12 @@ func (s *PublicreportQuickSetter) Apply(q *dialect.InsertQuery) {
vals[9] = psql.Raw("DEFAULT")
}
if !s.OrganizationID.IsUnset() {
vals[10] = psql.Arg(s.OrganizationID.MustGetNull())
} else {
vals[10] = psql.Raw("DEFAULT")
}
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
}))
}
@ -262,7 +279,7 @@ func (s PublicreportQuickSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
}
func (s PublicreportQuickSetter) Expressions(prefix ...string) []bob.Expression {
exprs := make([]bob.Expression, 0, 10)
exprs := make([]bob.Expression, 0, 11)
if s.ID.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
@ -334,6 +351,13 @@ func (s PublicreportQuickSetter) Expressions(prefix ...string) []bob.Expression
}})
}
if !s.OrganizationID.IsUnset() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "organization_id")...),
psql.Arg(s.OrganizationID),
}})
}
return exprs
}
@ -560,6 +584,30 @@ func (o PublicreportQuickSlice) ReloadAll(ctx context.Context, exec bob.Executor
return nil
}
// Organization starts a query for related objects on organization
func (o *PublicreportQuick) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
return Organizations.Query(append(mods,
sm.Where(Organizations.Columns.ID.EQ(psql.Arg(o.OrganizationID))),
)...)
}
func (os PublicreportQuickSlice) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery {
pkOrganizationID := make(pgtypes.Array[null.Val[int32]], 0, len(os))
for _, o := range os {
if o == nil {
continue
}
pkOrganizationID = append(pkOrganizationID, o.OrganizationID)
}
PKArgExpr := psql.Select(sm.Columns(
psql.F("unnest", psql.Cast(psql.Arg(pkOrganizationID), "integer[]")),
))
return Organizations.Query(append(mods,
sm.Where(psql.Group(Organizations.Columns.ID).OP("IN", PKArgExpr)),
)...)
}
// Images starts a query for related objects on publicreport.image
func (o *PublicreportQuick) Images(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportImagesQuery {
return PublicreportImages.Query(append(mods,
@ -589,6 +637,54 @@ func (os PublicreportQuickSlice) Images(mods ...bob.Mod[*dialect.SelectQuery]) P
)...)
}
func attachPublicreportQuickOrganization0(ctx context.Context, exec bob.Executor, count int, publicreportQuick0 *PublicreportQuick, organization1 *Organization) (*PublicreportQuick, error) {
setter := &PublicreportQuickSetter{
OrganizationID: omitnull.From(organization1.ID),
}
err := publicreportQuick0.Update(ctx, exec, setter)
if err != nil {
return nil, fmt.Errorf("attachPublicreportQuickOrganization0: %w", err)
}
return publicreportQuick0, nil
}
func (publicreportQuick0 *PublicreportQuick) InsertOrganization(ctx context.Context, exec bob.Executor, related *OrganizationSetter) error {
var err error
organization1, err := Organizations.Insert(related).One(ctx, exec)
if err != nil {
return fmt.Errorf("inserting related objects: %w", err)
}
_, err = attachPublicreportQuickOrganization0(ctx, exec, 1, publicreportQuick0, organization1)
if err != nil {
return err
}
publicreportQuick0.R.Organization = organization1
organization1.R.Quicks = append(organization1.R.Quicks, publicreportQuick0)
return nil
}
func (publicreportQuick0 *PublicreportQuick) AttachOrganization(ctx context.Context, exec bob.Executor, organization1 *Organization) error {
var err error
_, err = attachPublicreportQuickOrganization0(ctx, exec, 1, publicreportQuick0, organization1)
if err != nil {
return err
}
publicreportQuick0.R.Organization = organization1
organization1.R.Quicks = append(organization1.R.Quicks, publicreportQuick0)
return nil
}
func attachPublicreportQuickImages0(ctx context.Context, exec bob.Executor, count int, publicreportQuick0 *PublicreportQuick, publicreportImages2 PublicreportImageSlice) (PublicreportQuickImageSlice, error) {
setters := make([]*PublicreportQuickImageSetter, count)
for i := range count {
@ -665,6 +761,7 @@ type publicreportQuickWhere[Q psql.Filterable] struct {
ReporterPhone psql.WhereMod[Q, string]
Address psql.WhereMod[Q, string]
Status psql.WhereMod[Q, enums.PublicreportReportstatustype]
OrganizationID psql.WhereNullMod[Q, int32]
}
func (publicreportQuickWhere[Q]) AliasedAs(alias string) publicreportQuickWhere[Q] {
@ -683,6 +780,7 @@ func buildPublicreportQuickWhere[Q psql.Filterable](cols publicreportQuickColumn
ReporterPhone: psql.Where[Q, string](cols.ReporterPhone),
Address: psql.Where[Q, string](cols.Address),
Status: psql.Where[Q, enums.PublicreportReportstatustype](cols.Status),
OrganizationID: psql.WhereNull[Q, int32](cols.OrganizationID),
}
}
@ -692,6 +790,18 @@ func (o *PublicreportQuick) Preload(name string, retrieved any) error {
}
switch name {
case "Organization":
rel, ok := retrieved.(*Organization)
if !ok {
return fmt.Errorf("publicreportQuick cannot load %T as %q", retrieved, name)
}
o.R.Organization = rel
if rel != nil {
rel.R.Quicks = PublicreportQuickSlice{o}
}
return nil
case "Images":
rels, ok := retrieved.(PublicreportImageSlice)
if !ok {
@ -711,22 +821,48 @@ func (o *PublicreportQuick) Preload(name string, retrieved any) error {
}
}
type publicreportQuickPreloader struct{}
type publicreportQuickPreloader struct {
Organization func(...psql.PreloadOption) psql.Preloader
}
func buildPublicreportQuickPreloader() publicreportQuickPreloader {
return publicreportQuickPreloader{}
return publicreportQuickPreloader{
Organization: func(opts ...psql.PreloadOption) psql.Preloader {
return psql.Preload[*Organization, OrganizationSlice](psql.PreloadRel{
Name: "Organization",
Sides: []psql.PreloadSide{
{
From: PublicreportQuicks,
To: Organizations,
FromColumns: []string{"organization_id"},
ToColumns: []string{"id"},
},
},
}, Organizations.Columns.Names(), opts...)
},
}
}
type publicreportQuickThenLoader[Q orm.Loadable] struct {
Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
Images func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
}
func buildPublicreportQuickThenLoader[Q orm.Loadable]() publicreportQuickThenLoader[Q] {
type OrganizationLoadInterface interface {
LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
}
type ImagesLoadInterface interface {
LoadImages(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
}
return publicreportQuickThenLoader[Q]{
Organization: thenLoadBuilder[Q](
"Organization",
func(ctx context.Context, exec bob.Executor, retrieved OrganizationLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
return retrieved.LoadOrganization(ctx, exec, mods...)
},
),
Images: thenLoadBuilder[Q](
"Images",
func(ctx context.Context, exec bob.Executor, retrieved ImagesLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
@ -736,6 +872,61 @@ func buildPublicreportQuickThenLoader[Q orm.Loadable]() publicreportQuickThenLoa
}
}
// LoadOrganization loads the publicreportQuick's Organization into the .R struct
func (o *PublicreportQuick) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if o == nil {
return nil
}
// Reset the relationship
o.R.Organization = nil
related, err := o.Organization(mods...).One(ctx, exec)
if err != nil {
return err
}
related.R.Quicks = PublicreportQuickSlice{o}
o.R.Organization = related
return nil
}
// LoadOrganization loads the publicreportQuick's Organization into the .R struct
func (os PublicreportQuickSlice) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if len(os) == 0 {
return nil
}
organizations, err := os.Organization(mods...).All(ctx, exec)
if err != nil {
return err
}
for _, o := range os {
if o == nil {
continue
}
for _, rel := range organizations {
if !o.OrganizationID.IsValue() {
continue
}
if !(o.OrganizationID.IsValue() && o.OrganizationID.MustGet() == rel.ID) {
continue
}
rel.R.Quicks = append(rel.R.Quicks, o)
o.R.Organization = rel
break
}
}
return nil
}
// LoadImages loads the publicreportQuick's Images into the .R struct
func (o *PublicreportQuick) LoadImages(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
if o == nil {
@ -915,6 +1106,7 @@ func (os PublicreportQuickSlice) LoadCountImages(ctx context.Context, exec bob.E
type publicreportQuickJoins[Q dialect.Joinable] struct {
typ string
Organization modAs[Q, organizationColumns]
Images modAs[Q, publicreportImageColumns]
}
@ -925,6 +1117,20 @@ func (j publicreportQuickJoins[Q]) aliasedAs(alias string) publicreportQuickJoin
func buildPublicreportQuickJoins[Q dialect.Joinable](cols publicreportQuickColumns, typ string) publicreportQuickJoins[Q] {
return publicreportQuickJoins[Q]{
typ: typ,
Organization: modAs[Q, organizationColumns]{
c: Organizations.Columns,
f: func(to organizationColumns) bob.Mod[Q] {
mods := make(mods.QueryMods[Q], 0, 1)
{
mods = append(mods, dialect.Join[Q](typ, Organizations.Name().As(to.Alias())).On(
to.ID.EQ(cols.OrganizationID),
))
}
return mods
},
},
Images: modAs[Q, publicreportImageColumns]{
c: PublicreportImages.Columns,
f: func(to publicreportImageColumns) bob.Mod[Q] {

11
go.mod
View file

@ -34,13 +34,19 @@ require (
require (
github.com/ajg/form v1.5.1 // indirect
github.com/beevik/etree v1.1.0 // indirect
github.com/dsoprea/go-exif-extra v0.0.0-20210513050430-a8c8bb657ad5 // indirect
github.com/dsoprea/go-exif/v3 v3.0.1 // indirect
github.com/dsoprea/go-heic-exif-extractor/v2 v2.0.0-20210512044107-62067e44c235 // indirect
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb // indirect
github.com/dsoprea/go-jpeg-image-structure/v2 v2.0.0-20221012074422-4f3f7e934102 // indirect
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c // indirect
github.com/dsoprea/go-png-image-structure/v2 v2.0.0-20210512044023-23bdd883ee8e // indirect
github.com/dsoprea/go-tiff-image-structure/v2 v2.0.0-20210512044046-dc78da6a809b // indirect
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
github.com/dsoprea/go-webp-image-structure v0.0.0-20210512044215-f98af2b0401e // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/evanoberholster/imagemeta v0.3.1 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
@ -64,20 +70,23 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/tidwall/geoindex v1.4.4 // indirect
github.com/tidwall/gjson v1.12.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/rtree v1.3.1 // indirect
github.com/tidwall/sjson v1.2.4 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/twilio/twilio-go v1.29.1 // indirect
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
go.uber.org/multierr v1.11.0 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/image v0.0.0-20200618115811-c13761719519 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect

224
go.sum
View file

@ -1,7 +1,26 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Gleipnir-Technology/arcgis-go v0.0.5 h1:7UdgFZv7bnmLqkvGLivKurLKICmwZGWctPxESjDjeA8=
github.com/Gleipnir-Technology/arcgis-go v0.0.5/go.mod h1:Stx2sn5Lvuyhy4SaTQpbLNCAfenboDINi/UU5gQvz4k=
github.com/Gleipnir-Technology/go-geojson2h3/v2 v2.0.0 h1:6OMVxoiX9r7dEkIyYYKtSu7I2UDq64dww4JxJTo3p78=
@ -22,6 +41,11 @@ github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
@ -45,16 +69,25 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dsoprea/go-exif-extra v0.0.0-20210513050430-a8c8bb657ad5 h1:F5HkHi38eOQECRJTJIV1Amn+J5q2atJf2feGPJ8/v+U=
github.com/dsoprea/go-exif-extra v0.0.0-20210513050430-a8c8bb657ad5/go.mod h1:9RNGsP4bsNJg7MDbFLmCw1lovrpGB2xCOjzyugh+4iY=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717071058-9393e7afd446/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210428042052-dca55bf8ca15/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512055020-8213cfabc61b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-exif/v3 v3.0.0-20221003160559-cf5cd88aa559/go.mod h1:rW6DMEv25U9zCtE5ukC7ttBRllXj7g7TAHl7tQrT5No=
github.com/dsoprea/go-exif/v3 v3.0.0-20221003171958-de6cb6e380a8/go.mod h1:akyZEJZ/k5bmbC9gA612ZLQkcED8enS9vuTiuAkENr0=
github.com/dsoprea/go-exif/v3 v3.0.1 h1:/IE4iW7gvY7BablV1XY0unqhMv26EYpOquVMwoBo/wc=
github.com/dsoprea/go-exif/v3 v3.0.1/go.mod h1:10HkA1Wz3h398cDP66L+Is9kKDmlqlIJGPv8pk4EWvc=
github.com/dsoprea/go-heic-exif-extractor/v2 v2.0.0-20210512044107-62067e44c235 h1:a/XFkZdudAjXegNFRIf5vFjsF9LgFbiR5kjfHJZfIRA=
github.com/dsoprea/go-heic-exif-extractor/v2 v2.0.0-20210512044107-62067e44c235/go.mod h1:3mWA3lvkafMCuqoYKYXx/9YQgonsiAXf+KPSNlB/ZtI=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb h1:gwjJjUr6FY7zAWVEueFPrcRHhd9+IK81TcItbqw2du4=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
github.com/dsoprea/go-jpeg-image-structure/v2 v2.0.0-20210512043942-b434301c6836/go.mod h1:WaARaUjQuSuDCDFAiU/GwzfxMTJBulfEhqEA2Tx6B4Y=
github.com/dsoprea/go-jpeg-image-structure/v2 v2.0.0-20221012074422-4f3f7e934102 h1:gmTXQdSuuuORRFPTS2uaYpAXU5oUNkXdeYSlZe5NvsE=
github.com/dsoprea/go-jpeg-image-structure/v2 v2.0.0-20221012074422-4f3f7e934102/go.mod h1:WaARaUjQuSuDCDFAiU/GwzfxMTJBulfEhqEA2Tx6B4Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
@ -63,6 +96,12 @@ github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c h1:7j5aWACOzROpr+dvMtu8GnI97g9ShLWD72XIELMgn+c=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA=
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw=
github.com/dsoprea/go-png-image-structure/v2 v2.0.0-20210512044023-23bdd883ee8e h1:7xT+Xgi019P9KVdcl+QUnSrgKCwIZWqkPNk5GygFTsw=
github.com/dsoprea/go-png-image-structure/v2 v2.0.0-20210512044023-23bdd883ee8e/go.mod h1:scnx0wQSM7UiCMK66dSdiPZvL2hl6iF5DvpZ7uT59MY=
github.com/dsoprea/go-tiff-image-structure/v2 v2.0.0-20210512044046-dc78da6a809b h1:r5TpplS/qPIevKTw6B9ft3p00FP6Flp3lXizranDiVQ=
github.com/dsoprea/go-tiff-image-structure/v2 v2.0.0-20210512044046-dc78da6a809b/go.mod h1:O3HgJ0u+ZTGEk2HZq4/7OvE8QPXWrDM2I9hrD8Qq0o4=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
@ -70,10 +109,17 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003142440-7a1927d49d9d/go.mod h1:LV
github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU=
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw=
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8=
github.com/dsoprea/go-webp-image-structure v0.0.0-20210512044215-f98af2b0401e h1:Hj7L0xxjASwligRr2F2qy7i4UOk422xcZDvWQSU4m8I=
github.com/dsoprea/go-webp-image-structure v0.0.0-20210512044215-f98af2b0401e/go.mod h1:SRCiMUH7zHuGUQAEnxmURDSsXUIQZfCrQiIkywxxnSs=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807/go.mod h1:Xoiu5VdKMvbRgHuY7+z64lhu/7lvax/22nzASF6GrO8=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanoberholster/imagemeta v0.3.1 h1:E4GUjXcvlVMjP9joN25+bBNf3Al3MTTfMqCrDOCW+LE=
github.com/evanoberholster/imagemeta v0.3.1/go.mod h1:V0vtDJmjTqvwAYO8r+u33NRVIMXQb0qSqEfImoKEiXM=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
@ -88,6 +134,8 @@ github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWE
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@ -109,14 +157,42 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
@ -130,8 +206,12 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jaswdr/faker/v2 v2.8.1 h1:2AcPgHDBXYQregFUH9LgVZKfFupc4SIquYhp29sf5wQ=
github.com/jaswdr/faker/v2 v2.8.1/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68=
github.com/jdeng/goheif v0.0.0-20200323230657-a0d6a8b3e68f/go.mod h1:G7IyA3/eR9IFmUIPdyP3c0l4ZaqEvXAk876WfaQ8plc=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@ -205,10 +285,12 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM=
github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc=
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
@ -216,6 +298,9 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
@ -263,6 +348,8 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/rtree v1.3.1 h1:xu3vJPKJrmGce7YJcFUCoqLrp9DTUEJBnVgdPSXHgHs=
github.com/tidwall/rtree v1.3.1/go.mod h1:S+JSsqPTI8LfWA4xHBo5eXzie8WJLVFeppAutSegl6M=
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
@ -281,10 +368,15 @@ github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfP
github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07/go.mod h1:Ak17IJ037caFp4jpCw/iQQ7/W74Sqpb1YuKJU6HTKfM=
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4=
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY=
github.com/wayneashleyberry/terminal-dimensions v1.0.0/go.mod h1:PW2XrtV6KmKOPhuf7wbtcmw1/IFnC39mryRET2XbxeE=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
@ -297,24 +389,67 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34=
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
@ -324,14 +459,35 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -355,7 +511,10 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
@ -363,8 +522,32 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
@ -372,6 +555,39 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
@ -392,6 +608,11 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
@ -400,3 +621,6 @@ modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View file

@ -52,11 +52,11 @@ func main() {
sr := nidussync.Router()
hr.Map("", sr) // default
hr.Map("*", sr) // default
hr.Map(config.URLReport, publicreport.Router()) // report.mosquitoes.online
hr.Map(config.URLSync, sr)
hr.Map(config.DomainRMO, publicreport.Router()) // report.mosquitoes.online
hr.Map(config.DomainNidus, sr)
r.Mount("/", hr)
log.Info().Str("report url", config.URLReport).Str("sync url", config.URLSync).Msg("Serving at URLs")
log.Info().Str("report url", config.DomainRMO).Str("sync url", config.DomainNidus).Msg("Serving at URLs")
// Start up background processes
ctx, cancel := context.WithCancel(context.Background())

View file

@ -2,30 +2,50 @@ package platform
import (
"context"
"errors"
"fmt"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/rs/zerolog/log"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/sm"
)
func DistrictForLocation(ctx context.Context, lng float64, lat float64) (*models.ImportDistrict, error) {
rows, err := models.ImportDistricts.Query(
func DistrictForLocation(ctx context.Context, lng float64, lat float64) (*models.ImportDistrict, *models.Organization, error) {
districts, err := models.ImportDistricts.Query(
sm.Where(
psql.F("ST_Contains", psql.Raw("geom_4326"), psql.F("ST_SetSRID", psql.F("ST_MakePoint", psql.Arg(lng), psql.Arg(lat)), psql.Arg(4326))),
),
).All(ctx, db.PGInstance.BobDB)
log.Debug().Int("len", len(districts)).Float64("lng", lng).Float64("lat", lat).Msg("Attempting district match")
if err != nil {
return nil, fmt.Errorf("failed to query district: %w", err)
return nil, nil, fmt.Errorf("failed to query district: %w", err)
}
switch len(rows) {
switch len(districts) {
case 0:
return nil, nil
return nil, nil, nil
case 1:
return rows[0], nil
district := districts[0]
organizations, err := models.Organizations.Query(
sm.Where(
models.Organizations.Columns.ImportDistrictGid.EQ(psql.Arg(district.Gid)),
),
).All(ctx, db.PGInstance.BobDB)
if err != nil {
return nil, nil, fmt.Errorf("failed to query organization: %w", err)
}
switch len(organizations) {
case 0:
return nil, nil, nil
case 1:
return district, organizations[0], nil
default:
return nil, nil
return nil, nil, errors.New("too many organizations")
}
default:
return nil, nil, errors.New("too many districts")
}
}

View file

@ -8,9 +8,6 @@ import (
"github.com/rs/zerolog/log"
)
type ContextRegisterNotificationsComplete struct {
ReportID string
}
type ContextRoot struct{}
var (

View file

@ -13,21 +13,27 @@ import (
"net/http"
"time"
"github.com/aarondl/opt/omit"
"github.com/dsoprea/go-exif/v3"
exifcommon "github.com/dsoprea/go-exif/v3/common"
//"github.com/dsoprea/go-jpeg-image-structure/v2"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/userfile"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
"github.com/rwcarlsen/goexif/exif"
"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/dialect/psql"
"github.com/stephenafamo/bob/dialect/psql/um"
//exif "github.com/rwcarlsen/goexif/exif"
//"github.com/dsoprea/go-exif-extra/format"
)
type GPS struct {
Latitude float64
Longitude float64
}
type ExifCollection struct {
GPS *exif.GpsInfo
GPS *GPS
Tags map[string]string
}
@ -42,43 +48,30 @@ type ImageUpload struct {
UUID uuid.UUID
}
func extractExif(file_bytes []byte) (result ExifCollection, err error) {
func extractExif(content_type string, file_bytes []byte) (result ExifCollection, err error) {
/*
Using "github.com/evanoberholster/imagemeta"
meta, err := imagemeta.Decode(bytes.NewReader(file_bytes))
if err != nil {
return result, fmt.Errorf("Failed to decode image meta: %w", err)
}
result.GPS = &GPS{
Latitude: meta.GPS.Latitude(),
Longitude: meta.GPS.Longitude(),
}
return result, err
*/
raw_exif, err := exif.SearchAndExtractExifWithReader(bytes.NewReader(file_bytes))
exif, err := exif.Decode(bytes.NewReader(file_bytes))
if err != nil {
return result, fmt.Errorf("Failed to find exif: %w", err)
return result, fmt.Errorf("Failed to decode image meta: %w", err)
}
im, err := exifcommon.NewIfdMappingWithStandard()
if err != nil {
return result, fmt.Errorf("Failed to create new idf mapping: %w", err)
lat, lng, _ := exif.LatLong()
result.GPS = &GPS{
Latitude: lat,
Longitude: lng,
}
ti := exif.NewTagIndex()
_, index, err := exif.Collect(im, ti, raw_exif)
if err != nil {
return result, fmt.Errorf("Failed to collect exif: %w", err)
}
ifd, err := index.RootIfd.ChildWithIfdPath(exifcommon.IfdGpsInfoStandardIfdIdentity)
if err != nil {
return result, fmt.Errorf("Failed to find gps exif: %w", err)
}
gi, err := ifd.GpsInfo()
if err != nil {
log.Info().Err(err).Msg("Failed to get GPS info for uploaded image")
result.GPS = nil
} else {
result.GPS = gi
}
result.Tags = make(map[string]string, 0)
tags, _, err := exif.GetFlatExifData(raw_exif, &exif.ScanOptions{})
if err != nil {
return result, fmt.Errorf("Failed to gather flat exif: %w", err)
}
for _, t := range tags {
result.Tags[t.TagName] = t.Formatted
}
log.Info().Str("GPS", fmt.Sprintf("%s", gi)).Int("count", len(result.Tags)).Msg("Extracted exif tags")
return result, nil
return result, err
}
func extractImageUpload(headers *multipart.FileHeader) (upload ImageUpload, err error) {
@ -91,11 +84,12 @@ func extractImageUpload(headers *multipart.FileHeader) (upload ImageUpload, err
file_bytes, err := io.ReadAll(file)
content_type := http.DetectContentType(file_bytes)
exif, err := extractExif(file_bytes)
exif, err := extractExif(content_type, file_bytes)
if err != nil {
//return upload, fmt.Errorf("Failed to extract EXIF data: %w", err)
log.Warn().Err(err).Msg("Failed to extract EXIF data")
}
log.Debug().Float64("lat", exif.GPS.Latitude).Float64("lng", exif.GPS.Longitude).Msg("extracted GPS from exif")
i, format, err := image.Decode(bytes.NewReader(file_bytes))
if err != nil {
@ -143,7 +137,8 @@ func saveImageUploads(ctx context.Context, tx bob.Tx, uploads []ImageUpload) (mo
ContentType: omit.From(u.ContentType),
Created: omit.From(time.Now()),
//Location: omitnull.From(nil),
//Location: psql.Raw("NULL"),
Location: omitnull.FromPtr[string](nil),
ResolutionX: omit.From(int32(u.Bounds.Max.X)),
ResolutionY: omit.From(int32(u.Bounds.Max.Y)),
StorageUUID: omit.From(u.UUID),
@ -158,7 +153,7 @@ func saveImageUploads(ctx context.Context, tx bob.Tx, uploads []ImageUpload) (mo
if u.Exif.GPS != nil {
_, err = psql.Update(
um.Table("publicreport.image"),
um.SetCol("location").To(fmt.Sprintf("ST_GeometryFromText('Point(%f %f)')", u.Exif.GPS.Longitude.Decimal(), u.Exif.GPS.Latitude.Decimal())),
um.SetCol("location").To(fmt.Sprintf("ST_GeometryFromText('Point(%f %f)')", u.Exif.GPS.Longitude, u.Exif.GPS.Latitude)),
um.Where(psql.Quote("id").EQ(psql.Arg(image.ID))),
).Exec(ctx, tx)
}
@ -171,10 +166,12 @@ func saveImageUploads(ctx context.Context, tx bob.Tx, uploads []ImageUpload) (mo
Value: omit.From(v),
})
}
if len(exif_setters) > 0 {
_, err = models.PublicreportImageExifs.Insert(bob.ToMods(exif_setters...)).Exec(ctx, tx)
if err != nil {
return images, fmt.Errorf("Failed to create photo exif records: %w", err)
}
}
images = append(images, image)
log.Info().Int32("id", image.ID).Int("tags", len(u.Exif.Tags)).Msg("Saved an uploaded file to the database")
}

View file

@ -1,6 +1,7 @@
package publicreport
import (
"context"
"fmt"
"net/http"
"strconv"
@ -8,11 +9,13 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/background"
"github.com/Gleipnir-Technology/nidus-sync/comms"
"github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
"github.com/Gleipnir-Technology/nidus-sync/platform"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/rs/zerolog/log"
@ -21,10 +24,18 @@ import (
"github.com/stephenafamo/bob/dialect/psql/um"
)
type ContextQuick struct{}
type ContextQuickSubmitComplete struct {
type ContentQuick struct{}
type ContentQuickSubmitComplete struct {
District *District
ReportID string
}
type ContentRegisterNotificationsComplete struct {
ReportID string
}
type District struct {
LogoURL string
Name string
}
var (
quickT = buildTemplate("quick", "base")
@ -36,16 +47,45 @@ func getQuick(w http.ResponseWriter, r *http.Request) {
htmlpage.RenderOrError(
w,
quickT,
ContextQuick{},
ContentQuick{},
)
}
func getQuickSubmitComplete(w http.ResponseWriter, r *http.Request) {
report := r.URL.Query().Get("report")
ctx := r.Context()
report_id := r.URL.Query().Get("report")
report, err := models.PublicreportQuicks.Query(
models.SelectWhere.PublicreportQuicks.PublicID.EQ(report_id),
).One(ctx, db.PGInstance.BobDB)
if err != nil {
respondError(w, "Failed to get report", err, http.StatusInternalServerError)
return
}
var district *District
if !report.OrganizationID.IsNull() {
org_id := report.OrganizationID.MustGet()
org, err := models.Organizations.Query(
models.Preload.Organization.ImportDistrictGidDistrict(),
models.SelectWhere.Organizations.ID.EQ(org_id),
).One(ctx, db.PGInstance.BobDB)
if err != nil {
respondError(w, "Failed to get org", err, http.StatusInternalServerError)
return
}
d := org.R.ImportDistrictGidDistrict
log.Debug().Int32("org_id", org.ID).Int32("d_gid", d.Gid).Msg("Getting district")
if d != nil {
district = &District{
LogoURL: config.MakeURLNidus("/api/district/%d/logo", org_id),
Name: d.Agency.GetOr("Unknown"),
}
}
}
htmlpage.RenderOrError(
w,
quickSubmitCompleteT,
ContextQuickSubmitComplete{
ReportID: report,
ContentQuickSubmitComplete{
District: district,
ReportID: report.PublicID,
},
)
}
@ -54,11 +94,38 @@ func getRegisterNotificationsComplete(w http.ResponseWriter, r *http.Request) {
htmlpage.RenderOrError(
w,
registerNotificationsCompleteT,
ContextRegisterNotificationsComplete{
ContentRegisterNotificationsComplete{
ReportID: report,
},
)
}
func matchDistrict(ctx context.Context, longitude, latitude float64, images []ImageUpload) (*int32, error) {
for _, image := range images {
if image.Exif.GPS == nil {
continue
}
_, org, err := platform.DistrictForLocation(ctx, image.Exif.GPS.Longitude, image.Exif.GPS.Latitude)
if err != nil {
log.Warn().Err(err).Msg("Failed to get district for location")
continue
}
if org != nil {
return &org.ID, nil
}
}
_, org, err := platform.DistrictForLocation(ctx, longitude, latitude)
if err != nil {
log.Warn().Err(err).Msg("Failed to get district for location")
return nil, fmt.Errorf("Failed to get district for location: %w", err)
}
if org == nil {
log.Debug().Err(err).Float64("lng", longitude).Float64("lat", latitude).Msg("No district match by report location")
return nil, nil
}
log.Debug().Err(err).Int32("org_id", org.ID).Float64("lng", longitude).Float64("lat", latitude).Msg("Found district match by report location")
return &org.ID, nil
}
func postQuick(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
if err != nil {
@ -92,11 +159,30 @@ func postQuick(w http.ResponseWriter, r *http.Request) {
}
defer tx.Rollback(ctx)
uploads, err := extractImageUploads(r)
log.Info().Int("len", len(uploads)).Msg("extracted uploads")
if err != nil {
respondError(w, "Failed to extract image uploads", err, http.StatusInternalServerError)
return
}
images, err := saveImageUploads(ctx, tx, uploads)
if err != nil {
respondError(w, "Failed to save image uploads", err, http.StatusInternalServerError)
return
}
organization_id, err := matchDistrict(ctx, longitude, latitude, uploads)
if err != nil {
log.Warn().Err(err).Msg("Failed to match district")
}
log.Info().Int("len", len(images)).Msg("saved uploads")
c, err := h3utils.GetCell(longitude, latitude, 15)
setter := models.PublicreportQuickSetter{
Address: omit.From(""),
Created: omit.From(time.Now()),
Comments: omit.From(comments),
OrganizationID: omitnull.FromPtr(organization_id),
//Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)),
H3cell: omitnull.From(c.String()),
PublicID: omit.From(u),
@ -119,18 +205,6 @@ func postQuick(w http.ResponseWriter, r *http.Request) {
return
}
log.Info().Float64("latitude", latitude).Float64("longitude", longitude).Msg("Got upload")
uploads, err := extractImageUploads(r)
log.Info().Int("len", len(uploads)).Msg("extracted uploads")
if err != nil {
respondError(w, "Failed to extract image uploads", err, http.StatusInternalServerError)
return
}
images, err := saveImageUploads(ctx, tx, uploads)
if err != nil {
respondError(w, "Failed to save image uploads", err, http.StatusInternalServerError)
return
}
log.Info().Int("len", len(images)).Msg("saved uploads")
if len(images) > 0 {
setters := make([]*models.PublicreportQuickImageSetter, 0)
for _, image := range images {

View file

@ -22,7 +22,7 @@ func getSearch(w http.ResponseWriter, r *http.Request) {
Search,
ContentSearch{
MapboxToken: config.MapboxToken,
URLTegola: config.URLTegola,
URLTegola: config.MakeURLTegola("/"),
},
)
}

View file

@ -38,6 +38,7 @@ type Report struct {
Address string
Comments string
Created time.Time
District string
ID string
Images []Image
Location string // GeoJSON
@ -175,6 +176,7 @@ func contentFromQuick(ctx context.Context, report_id string) (result ContentStat
result.Report.Address = quick.Address
result.Report.Comments = quick.Comments
result.Report.Created = quick.Created
result.Report.District = "Unknown"
result.Report.Reporter.Email = quick.ReporterEmail
result.Report.Reporter.Name = "-"
result.Report.Reporter.Phone = quick.ReporterPhone
@ -183,7 +185,7 @@ func contentFromQuick(ctx context.Context, report_id string) (result ContentStat
for _, image := range images {
result.Report.Images = append(result.Report.Images, Image{
Location: image.LocationJSON,
URL: fmt.Sprintf("https://%s/image/%s", config.RMODomain, image.StorageUUID),
URL: config.MakeURLReport("/image/%s", image.StorageUUID),
})
}
type LocationGeoJSON struct {

View file

@ -29,6 +29,11 @@
<span class="fs-4 fw-bold">{{.ReportID|publicReportID}}</span>
</div>
<p class="text-muted">Please save this ID for your reference.</p>
{{ if not (eq .District nil) }}
<p>Your report has been assigned to</p>
<p><b>{{ .District.Name }}</b></p>
<img src="{{ .District.LogoURL }}" width="256"/>
{{ end }}
</div>
<hr class="my-4">

View file

@ -82,8 +82,8 @@ document.addEventListener("DOMContentLoaded", onLoad);
<span>{{.Report.Created|timeSince}}</span>
</div>
<div class="col-md-4 mb-3">
<strong><i class="fas fa-hourglass-half me-2"></i>Next Step:</strong>
<span>July 19, 2023 (Estimated)</span>
<strong><i class="fas fa-hourglass-half me-2"></i>District:</strong>
<span>{{.Report.District}}</span>
</div>
</div>
</div>

View file

@ -284,7 +284,7 @@ func dashboard(ctx context.Context, w http.ResponseWriter, user *models.User) {
}
data := ContextDashboard{
Config: Config{
URLTegola: config.URLTegola,
URLTegola: config.MakeURLTegola("/"),
},
CountTraps: int(trapCount),
CountMosquitoSources: int(sourceCount),

View file

@ -49,7 +49,7 @@ func getQRCodeReport(w http.ResponseWriter, r *http.Request) {
if code == "" {
respondError(w, "There should always be a code", nil, http.StatusBadRequest)
}
content := config.MakeURLSync("/report/" + code)
content := config.MakeURLNidus("/report/%s", code)
// Get optional size parameter (default to 256)
size := 256
if sizeStr := r.URL.Query().Get("size"); sizeStr != "" {

View file

@ -2,6 +2,8 @@ package sync
import (
"net/http"
"net/url"
"strconv"
"github.com/Gleipnir-Technology/nidus-sync/auth"
"github.com/Gleipnir-Technology/nidus-sync/background"
@ -19,8 +21,33 @@ type ContextOauthPrompt struct {
User User
}
// Build the ArcGIS authorization URL with PKCE
func buildArcGISAuthURL(clientID string) string {
baseURL := "https://www.arcgis.com/sharing/rest/oauth2/authorize/"
params := url.Values{}
params.Add("client_id", clientID)
params.Add("redirect_uri", config.ArcGISOauthRedirectURL())
params.Add("response_type", "code")
//params.Add("code_challenge", generateCodeChallenge(codeVerifier))
//params.Add("code_challenge_method", "S256")
// See https://developers.arcgis.com/rest/users-groups-and-items/token/
// expiration is defined in minutes
var expiration int
if config.IsProductionEnvironment() {
// 2 weeks is the maximum allowed
expiration = 20160
} else {
expiration = 20
}
params.Add("expiration", strconv.Itoa(expiration))
return baseURL + "?" + params.Encode()
}
func getArcgisOauthBegin(w http.ResponseWriter, r *http.Request) {
authURL := config.BuildArcGISAuthURL(config.ClientID)
authURL := buildArcGISAuthURL(config.ClientID)
http.Redirect(w, r, authURL, http.StatusFound)
}
@ -41,7 +68,7 @@ func getArcgisOauthCallback(w http.ResponseWriter, r *http.Request) {
respondError(w, "Failed to handle access code", err, http.StatusInternalServerError)
return
}
http.Redirect(w, r, config.MakeURLSync("/"), http.StatusFound)
http.Redirect(w, r, config.MakeURLNidus("/"), http.StatusFound)
}
func getOAuthRefresh(w http.ResponseWriter, r *http.Request) {

View file

@ -41,11 +41,17 @@ func AudioFileContentWrite(audioUUID uuid.UUID, body io.Reader) error {
log.Info().Str("filepath", filepath).Msg("Save audio file content")
return nil
}
func ImageFileContentPathRaw(uid string) string {
return fmt.Sprintf("%s/%s.raw", config.FilesDirectoryUser, uid)
func ImageFileContentPathRawUser(uid string) string {
return imageFileContentPath(config.FilesDirectoryUser, uid, "raw")
}
func imageFileContentPathLogoPng(uid string) string {
return imageFileContentPath(config.FilesDirectoryLogo, uid, "png")
}
func imageFileContentPath(dir string, uid string, ext string) string {
return fmt.Sprintf("%s/%s.%s", dir, uid, ext)
}
func ImageFileContentWrite(uid uuid.UUID, body io.Reader) error {
filepath := ImageFileContentPathRaw(uid.String())
filepath := ImageFileContentPathRawUser(uid.String())
// Create file in configured directory
dst, err := os.Create(filepath)
@ -61,6 +67,11 @@ func ImageFileContentWrite(uid uuid.UUID, body io.Reader) error {
}
return nil
}
func ImageFileContentWriteLogo(w http.ResponseWriter, uid uuid.UUID) {
image_path := imageFileContentPathLogoPng(uid.String())
writeFileContent(w, image_path)
}
func PublicImageFileContentWrite(uid uuid.UUID, body io.Reader) error {
// Create file in configured directory
filepath := PublicImageFileContentPathRaw(uid.String())
@ -86,7 +97,10 @@ func PublicImageFileContentPathRaw(uid string) string {
func PublicImageFileToResponse(w http.ResponseWriter, uid string) {
image_path := PublicImageFileContentPathRaw(uid)
writeFileContent(w, image_path)
}
func writeFileContent(w http.ResponseWriter, image_path string) {
// Open the file
file, err := os.Open(image_path)
if err != nil {