diff --git a/background/background.go b/background/background.go index 79055e68..8ee030c4 100644 --- a/background/background.go +++ b/background/background.go @@ -5,14 +5,17 @@ import ( "fmt" "sync" + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/sm" commsemail "github.com/Gleipnir-Technology/nidus-sync/comms/email" "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/platform/email" "github.com/Gleipnir-Technology/nidus-sync/platform/text" "github.com/rs/zerolog/log" + "github.com/stephenafamo/scan" ) var waitGroup sync.WaitGroup @@ -20,10 +23,10 @@ var waitGroup sync.WaitGroup func Start(ctx context.Context) { newOAuthTokenChannel = make(chan struct{}, 10) - channelJobAudio = make(chan jobAudio, 100) // Buffered channel to prevent blocking - channelJobImportCSVPool = make(chan jobImportCSVPool, 100) // Buffered channel to prevent blocking - channelJobEmail = make(chan email.Job, 100) // Buffered channel to prevent blocking - channelJobText = make(chan text.Job, 100) // Buffered channel to prevent blocking + channelJobAudio = make(chan jobAudio, 100) // Buffered channel to prevent blocking + channelJobImportCSV = make(chan jobImportCSV, 100) // Buffered channel to prevent blocking + channelJobEmail = make(chan email.Job, 100) // Buffered channel to prevent blocking + channelJobText = make(chan text.Job, 100) // Buffered channel to prevent blocking waitGroup.Add(1) go func() { @@ -46,7 +49,7 @@ func Start(ctx context.Context) { waitGroup.Add(1) go func() { defer waitGroup.Done() - startWorkerCSV(ctx, channelJobImportCSVPool) + startWorkerCSV(ctx, channelJobImportCSV) }() waitGroup.Add(1) @@ -73,21 +76,33 @@ func WaitForExit() { } func addWaitingJobs(ctx context.Context) error { - rows, err := models.FileuploadFiles.Query( - models.SelectWhere.FileuploadFiles.Status.EQ( - enums.FileuploadFilestatustypeUploaded, + type Row_ struct { + ID int32 `db:"id"` + Type enums.FileuploadCsvtype `db:"type"` + } + rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( + sm.Columns( + "file.id AS id", + "csv.type_ AS type", ), - ).All(ctx, db.PGInstance.BobDB) + sm.From("fileupload.file").As("file"), + sm.InnerJoin("fileupload.csv").As("csv").OnEQ(psql.Raw("file.id"), psql.Raw("csv.file_id")), + sm.Where( + psql.Raw("file.status").EQ(psql.Arg(enums.FileuploadFilestatustypeUploaded)), + ), + ), scan.StructMapper[Row_]()) + if err != nil { return fmt.Errorf("Failed to query file uploads: %w", err) } for _, row := range rows { report_id := row.ID - job := jobImportCSVPool{ + job := jobImportCSV{ fileID: report_id, + type_: row.Type, } select { - case channelJobImportCSVPool <- job: + case channelJobImportCSV <- job: log.Info().Int32("report_id", report_id).Msg("CSV upload job queued") default: log.Warn().Int32("report_id", report_id).Msg("CSV upload job failed to queue, channel full") diff --git a/background/pool.go b/background/pool.go index e9f7f0b2..c8401359 100644 --- a/background/pool.go +++ b/background/pool.go @@ -4,34 +4,36 @@ import ( "context" //"fmt" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" "github.com/Gleipnir-Technology/nidus-sync/platform/csv" //"github.com/Gleipnir-Technology/nidus-sync/userfile" //"github.com/google/uuid" "github.com/rs/zerolog/log" ) -// represents a job to import a pool CSV file -type jobImportCSVPool struct { +type jobImportCSV struct { fileID int32 + type_ enums.FileuploadCsvtype } -var channelJobImportCSVPool chan jobImportCSVPool +var channelJobImportCSV chan jobImportCSV -func ProcessUpload(file_id int32) { - enqueueUploadJob(jobImportCSVPool{ +func ProcessUpload(file_id int32, t enums.FileuploadCsvtype) { + enqueueUploadJob(jobImportCSV{ fileID: file_id, + type_: t, }) } -func enqueueUploadJob(job jobImportCSVPool) { +func enqueueUploadJob(job jobImportCSV) { select { - case channelJobImportCSVPool <- job: + case channelJobImportCSV <- job: log.Info().Int32("file_id", job.fileID).Msg("Enqueued csv job") default: log.Warn().Int32("file_id", job.fileID).Msg("csv channel is full, dropping job") } } -func startWorkerCSV(ctx context.Context, channelJobImport chan jobImportCSVPool) { +func startWorkerCSV(ctx context.Context, channelJobImport chan jobImportCSV) { go func() { for { select { @@ -40,7 +42,7 @@ func startWorkerCSV(ctx context.Context, channelJobImport chan jobImportCSVPool) return case job := <-channelJobImport: log.Info().Int32("id", job.fileID).Msg("Processing CSV job") - err := csv.ProcessJob(ctx, job.fileID) + err := csv.ProcessJob(ctx, job.fileID, job.type_) if err != nil { log.Error().Err(err).Int32("id", job.fileID).Msg("Error processing CSV file") } diff --git a/db/dberrors/fileupload.flyover_aerial_service.bob.go b/db/dberrors/fileupload.flyover_aerial_service.bob.go new file mode 100644 index 00000000..45bc58b2 --- /dev/null +++ b/db/dberrors/fileupload.flyover_aerial_service.bob.go @@ -0,0 +1,17 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dberrors + +var FileuploadFlyoverAerialServiceErrors = &fileuploadFlyoverAerialServiceErrors{ + ErrUniqueFlyoverAerialServicePkey: &UniqueConstraintError{ + schema: "fileupload", + table: "flyover_aerial_service", + columns: []string{"id"}, + s: "flyover_aerial_service_pkey", + }, +} + +type fileuploadFlyoverAerialServiceErrors struct { + ErrUniqueFlyoverAerialServicePkey *UniqueConstraintError +} diff --git a/db/dbinfo/fileupload.flyover_aerial_service.bob.go b/db/dbinfo/fileupload.flyover_aerial_service.bob.go new file mode 100644 index 00000000..38398211 --- /dev/null +++ b/db/dbinfo/fileupload.flyover_aerial_service.bob.go @@ -0,0 +1,217 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dbinfo + +import "github.com/aarondl/opt/null" + +var FileuploadFlyoverAerialServices = Table[ + fileuploadFlyoverAerialServiceColumns, + fileuploadFlyoverAerialServiceIndexes, + fileuploadFlyoverAerialServiceForeignKeys, + fileuploadFlyoverAerialServiceUniques, + fileuploadFlyoverAerialServiceChecks, +]{ + Schema: "fileupload", + Name: "flyover_aerial_service", + Columns: fileuploadFlyoverAerialServiceColumns{ + Committed: column{ + Name: "committed", + DBType: "boolean", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Condition: column{ + Name: "condition", + DBType: "fileupload.poolconditiontype", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Created: column{ + Name: "created", + DBType: "timestamp without time zone", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + CreatorID: column{ + Name: "creator_id", + DBType: "integer", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + CSVFile: column{ + Name: "csv_file", + DBType: "integer", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Deleted: column{ + Name: "deleted", + DBType: "timestamp without time zone", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + Geom: column{ + Name: "geom", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + H3cell: column{ + Name: "h3cell", + DBType: "h3index", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + ID: column{ + Name: "id", + DBType: "integer", + Default: "nextval('fileupload.flyover_aerial_service_id_seq'::regclass)", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + OrganizationID: column{ + Name: "organization_id", + DBType: "integer", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + }, + Indexes: fileuploadFlyoverAerialServiceIndexes{ + FlyoverAerialServicePkey: index{ + Type: "btree", + Name: "flyover_aerial_service_pkey", + Columns: []indexColumn{ + { + Name: "id", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: true, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, + }, + PrimaryKey: &constraint{ + Name: "flyover_aerial_service_pkey", + Columns: []string{"id"}, + Comment: "", + }, + ForeignKeys: fileuploadFlyoverAerialServiceForeignKeys{ + FileuploadFlyoverAerialServiceFlyoverAerialServiceCreatorIDFkey: foreignKey{ + constraint: constraint{ + Name: "fileupload.flyover_aerial_service.flyover_aerial_service_creator_id_fkey", + Columns: []string{"creator_id"}, + Comment: "", + }, + ForeignTable: "user_", + ForeignColumns: []string{"id"}, + }, + FileuploadFlyoverAerialServiceFlyoverAerialServiceCSVFileFkey: foreignKey{ + constraint: constraint{ + Name: "fileupload.flyover_aerial_service.flyover_aerial_service_csv_file_fkey", + Columns: []string{"csv_file"}, + Comment: "", + }, + ForeignTable: "fileupload.csv", + ForeignColumns: []string{"file_id"}, + }, + FileuploadFlyoverAerialServiceFlyoverAerialServiceOrganizationIDFkey: foreignKey{ + constraint: constraint{ + Name: "fileupload.flyover_aerial_service.flyover_aerial_service_organization_id_fkey", + Columns: []string{"organization_id"}, + Comment: "", + }, + ForeignTable: "organization", + ForeignColumns: []string{"id"}, + }, + }, + + Comment: "", +} + +type fileuploadFlyoverAerialServiceColumns struct { + Committed column + Condition column + Created column + CreatorID column + CSVFile column + Deleted column + Geom column + H3cell column + ID column + OrganizationID column +} + +func (c fileuploadFlyoverAerialServiceColumns) AsSlice() []column { + return []column{ + c.Committed, c.Condition, c.Created, c.CreatorID, c.CSVFile, c.Deleted, c.Geom, c.H3cell, c.ID, c.OrganizationID, + } +} + +type fileuploadFlyoverAerialServiceIndexes struct { + FlyoverAerialServicePkey index +} + +func (i fileuploadFlyoverAerialServiceIndexes) AsSlice() []index { + return []index{ + i.FlyoverAerialServicePkey, + } +} + +type fileuploadFlyoverAerialServiceForeignKeys struct { + FileuploadFlyoverAerialServiceFlyoverAerialServiceCreatorIDFkey foreignKey + FileuploadFlyoverAerialServiceFlyoverAerialServiceCSVFileFkey foreignKey + FileuploadFlyoverAerialServiceFlyoverAerialServiceOrganizationIDFkey foreignKey +} + +func (f fileuploadFlyoverAerialServiceForeignKeys) AsSlice() []foreignKey { + return []foreignKey{ + f.FileuploadFlyoverAerialServiceFlyoverAerialServiceCreatorIDFkey, f.FileuploadFlyoverAerialServiceFlyoverAerialServiceCSVFileFkey, f.FileuploadFlyoverAerialServiceFlyoverAerialServiceOrganizationIDFkey, + } +} + +type fileuploadFlyoverAerialServiceUniques struct{} + +func (u fileuploadFlyoverAerialServiceUniques) AsSlice() []constraint { + return []constraint{} +} + +type fileuploadFlyoverAerialServiceChecks struct{} + +func (c fileuploadFlyoverAerialServiceChecks) AsSlice() []check { + return []check{} +} diff --git a/db/enums/enums.bob.go b/db/enums/enums.bob.go index 9aee274d..ed4419f7 100644 --- a/db/enums/enums.bob.go +++ b/db/enums/enums.bob.go @@ -986,11 +986,13 @@ func (e *Countrytype) Scan(value any) error { // Enum values for FileuploadCsvtype const ( FileuploadCsvtypePoollist FileuploadCsvtype = "PoolList" + FileuploadCsvtypeFlyover FileuploadCsvtype = "Flyover" ) func AllFileuploadCsvtype() []FileuploadCsvtype { return []FileuploadCsvtype{ FileuploadCsvtypePoollist, + FileuploadCsvtypeFlyover, } } @@ -1002,7 +1004,8 @@ func (e FileuploadCsvtype) String() string { func (e FileuploadCsvtype) Valid() bool { switch e { - case FileuploadCsvtypePoollist: + case FileuploadCsvtypePoollist, + FileuploadCsvtypeFlyover: return true default: return false diff --git a/db/factory/bobfactory_context.bob.go b/db/factory/bobfactory_context.bob.go index 906dd5fd..8e600281 100644 --- a/db/factory/bobfactory_context.bob.go +++ b/db/factory/bobfactory_context.bob.go @@ -236,10 +236,11 @@ var ( fieldseekerSyncRelOrganizationCtx = newContextual[bool]("fieldseeker_sync.organization.fieldseeker_sync.fieldseeker_sync_organization_id_fkey") // Relationship Contexts for fileupload.csv - fileuploadCSVWithParentsCascadingCtx = newContextual[bool]("fileuploadCSVWithParentsCascading") - fileuploadCSVRelFileCtx = newContextual[bool]("fileupload.csv.fileupload.file.fileupload.csv.csv_file_id_fkey") - fileuploadCSVRelCSVFileErrorCSVSCtx = newContextual[bool]("fileupload.csv.fileupload.error_csv.fileupload.error_csv.error_csv_csv_file_id_fkey") - fileuploadCSVRelCSVFilePoolsCtx = newContextual[bool]("fileupload.csv.fileupload.pool.fileupload.pool.pool_csv_file_fkey") + fileuploadCSVWithParentsCascadingCtx = newContextual[bool]("fileuploadCSVWithParentsCascading") + fileuploadCSVRelFileCtx = newContextual[bool]("fileupload.csv.fileupload.file.fileupload.csv.csv_file_id_fkey") + fileuploadCSVRelCSVFileErrorCSVSCtx = newContextual[bool]("fileupload.csv.fileupload.error_csv.fileupload.error_csv.error_csv_csv_file_id_fkey") + fileuploadCSVRelCSVFileFlyoverAerialServicesCtx = newContextual[bool]("fileupload.csv.fileupload.flyover_aerial_service.fileupload.flyover_aerial_service.flyover_aerial_service_csv_file_fkey") + fileuploadCSVRelCSVFilePoolsCtx = newContextual[bool]("fileupload.csv.fileupload.pool.fileupload.pool.pool_csv_file_fkey") // Relationship Contexts for fileupload.error_csv fileuploadErrorCSVWithParentsCascadingCtx = newContextual[bool]("fileuploadErrorCSVWithParentsCascading") @@ -257,6 +258,12 @@ var ( fileuploadFileRelOrganizationCtx = newContextual[bool]("fileupload.file.organization.fileupload.file.file_organization_id_fkey") fileuploadFileRelSitesCtx = newContextual[bool]("fileupload.file.site.site.site_file_id_fkey") + // Relationship Contexts for fileupload.flyover_aerial_service + fileuploadFlyoverAerialServiceWithParentsCascadingCtx = newContextual[bool]("fileuploadFlyoverAerialServiceWithParentsCascading") + fileuploadFlyoverAerialServiceRelCreatorUserCtx = newContextual[bool]("fileupload.flyover_aerial_service.user_.fileupload.flyover_aerial_service.flyover_aerial_service_creator_id_fkey") + fileuploadFlyoverAerialServiceRelCSVFileCSVCtx = newContextual[bool]("fileupload.csv.fileupload.flyover_aerial_service.fileupload.flyover_aerial_service.flyover_aerial_service_csv_file_fkey") + fileuploadFlyoverAerialServiceRelOrganizationCtx = newContextual[bool]("fileupload.flyover_aerial_service.organization.fileupload.flyover_aerial_service.flyover_aerial_service_organization_id_fkey") + // Relationship Contexts for fileupload.pool fileuploadPoolWithParentsCascadingCtx = newContextual[bool]("fileuploadPoolWithParentsCascading") fileuploadPoolRelCreatorUserCtx = newContextual[bool]("fileupload.pool.user_.fileupload.pool.pool_creator_id_fkey") @@ -350,6 +357,7 @@ var ( organizationRelZones2sCtx = newContextual[bool]("fieldseeker.zones2.organization.fieldseeker.zones2.zones2_organization_id_fkey") organizationRelFieldseekerSyncsCtx = newContextual[bool]("fieldseeker_sync.organization.fieldseeker_sync.fieldseeker_sync_organization_id_fkey") organizationRelFilesCtx = newContextual[bool]("fileupload.file.organization.fileupload.file.file_organization_id_fkey") + organizationRelFlyoverAerialServicesCtx = newContextual[bool]("fileupload.flyover_aerial_service.organization.fileupload.flyover_aerial_service.flyover_aerial_service_organization_id_fkey") organizationRelPoolsCtx = newContextual[bool]("fileupload.pool.organization.fileupload.pool.pool_organization_id_fkey") organizationRelH3AggregationsCtx = newContextual[bool]("h3_aggregation.organization.h3_aggregation.h3_aggregation_organization_id_fkey") organizationRelNoteAudiosCtx = newContextual[bool]("note_audio.organization.note_audio.note_audio_organization_id_fkey") @@ -481,6 +489,7 @@ var ( userRelPublicUserUserCtx = newContextual[bool]("arcgis.user_.user_.arcgis.user_.user__public_user_id_fkey") userRelCreatorComplianceReportRequestsCtx = newContextual[bool]("compliance_report_request.user_.compliance_report_request.compliance_report_request_creator_fkey") userRelCreatorFilesCtx = newContextual[bool]("fileupload.file.user_.fileupload.file.file_creator_id_fkey") + userRelCreatorFlyoverAerialServicesCtx = newContextual[bool]("fileupload.flyover_aerial_service.user_.fileupload.flyover_aerial_service.flyover_aerial_service_creator_id_fkey") userRelFileuploadPoolCtx = newContextual[bool]("fileupload.pool.user_.fileupload.pool.pool_creator_id_fkey") userRelCreatorNoteAudiosCtx = newContextual[bool]("note_audio.user_.note_audio.note_audio_creator_id_fkey") userRelDeletorNoteAudiosCtx = newContextual[bool]("note_audio.user_.note_audio.note_audio_deletor_id_fkey") diff --git a/db/factory/bobfactory_main.bob.go b/db/factory/bobfactory_main.bob.go index 44dcdcdc..52145647 100644 --- a/db/factory/bobfactory_main.bob.go +++ b/db/factory/bobfactory_main.bob.go @@ -72,6 +72,7 @@ type Factory struct { baseFileuploadErrorCSVMods FileuploadErrorCSVModSlice baseFileuploadErrorFileMods FileuploadErrorFileModSlice baseFileuploadFileMods FileuploadFileModSlice + baseFileuploadFlyoverAerialServiceMods FileuploadFlyoverAerialServiceModSlice baseFileuploadPoolMods FileuploadPoolModSlice baseGeographyColumnMods GeographyColumnModSlice baseGeometryColumnMods GeometryColumnModSlice @@ -2706,6 +2707,9 @@ func (f *Factory) FromExistingFileuploadCSV(m *models.FileuploadCSV) *Fileupload if len(m.R.CSVFileErrorCSVS) > 0 { FileuploadCSVMods.AddExistingCSVFileErrorCSVS(m.R.CSVFileErrorCSVS...).Apply(ctx, o) } + if len(m.R.CSVFileFlyoverAerialServices) > 0 { + FileuploadCSVMods.AddExistingCSVFileFlyoverAerialServices(m.R.CSVFileFlyoverAerialServices...).Apply(ctx, o) + } if len(m.R.CSVFilePools) > 0 { FileuploadCSVMods.AddExistingCSVFilePools(m.R.CSVFilePools...).Apply(ctx, o) } @@ -2827,6 +2831,50 @@ func (f *Factory) FromExistingFileuploadFile(m *models.FileuploadFile) *Fileuplo return o } +func (f *Factory) NewFileuploadFlyoverAerialService(mods ...FileuploadFlyoverAerialServiceMod) *FileuploadFlyoverAerialServiceTemplate { + return f.NewFileuploadFlyoverAerialServiceWithContext(context.Background(), mods...) +} + +func (f *Factory) NewFileuploadFlyoverAerialServiceWithContext(ctx context.Context, mods ...FileuploadFlyoverAerialServiceMod) *FileuploadFlyoverAerialServiceTemplate { + o := &FileuploadFlyoverAerialServiceTemplate{f: f} + + if f != nil { + f.baseFileuploadFlyoverAerialServiceMods.Apply(ctx, o) + } + + FileuploadFlyoverAerialServiceModSlice(mods).Apply(ctx, o) + + return o +} + +func (f *Factory) FromExistingFileuploadFlyoverAerialService(m *models.FileuploadFlyoverAerialService) *FileuploadFlyoverAerialServiceTemplate { + o := &FileuploadFlyoverAerialServiceTemplate{f: f, alreadyPersisted: true} + + o.Committed = func() bool { return m.Committed } + o.Condition = func() enums.FileuploadPoolconditiontype { return m.Condition } + o.Created = func() time.Time { return m.Created } + o.CreatorID = func() int32 { return m.CreatorID } + o.CSVFile = func() int32 { return m.CSVFile } + o.Deleted = func() null.Val[time.Time] { return m.Deleted } + o.Geom = func() null.Val[string] { return m.Geom } + o.H3cell = func() null.Val[string] { return m.H3cell } + o.ID = func() int32 { return m.ID } + o.OrganizationID = func() int32 { return m.OrganizationID } + + ctx := context.Background() + if m.R.CreatorUser != nil { + FileuploadFlyoverAerialServiceMods.WithExistingCreatorUser(m.R.CreatorUser).Apply(ctx, o) + } + if m.R.CSVFileCSV != nil { + FileuploadFlyoverAerialServiceMods.WithExistingCSVFileCSV(m.R.CSVFileCSV).Apply(ctx, o) + } + if m.R.Organization != nil { + FileuploadFlyoverAerialServiceMods.WithExistingOrganization(m.R.Organization).Apply(ctx, o) + } + + return o +} + func (f *Factory) NewFileuploadPool(mods ...FileuploadPoolMod) *FileuploadPoolTemplate { return f.NewFileuploadPoolWithContext(context.Background(), mods...) } @@ -3430,6 +3478,9 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization if len(m.R.Files) > 0 { OrganizationMods.AddExistingFiles(m.R.Files...).Apply(ctx, o) } + if len(m.R.FlyoverAerialServices) > 0 { + OrganizationMods.AddExistingFlyoverAerialServices(m.R.FlyoverAerialServices...).Apply(ctx, o) + } if len(m.R.Pools) > 0 { OrganizationMods.AddExistingPools(m.R.Pools...).Apply(ctx, o) } @@ -4404,6 +4455,9 @@ func (f *Factory) FromExistingUser(m *models.User) *UserTemplate { if len(m.R.CreatorFiles) > 0 { UserMods.AddExistingCreatorFiles(m.R.CreatorFiles...).Apply(ctx, o) } + if len(m.R.CreatorFlyoverAerialServices) > 0 { + UserMods.AddExistingCreatorFlyoverAerialServices(m.R.CreatorFlyoverAerialServices...).Apply(ctx, o) + } if len(m.R.FileuploadPool) > 0 { UserMods.AddExistingFileuploadPool(m.R.FileuploadPool...).Apply(ctx, o) } @@ -4862,6 +4916,14 @@ func (f *Factory) AddBaseFileuploadFileMod(mods ...FileuploadFileMod) { f.baseFileuploadFileMods = append(f.baseFileuploadFileMods, mods...) } +func (f *Factory) ClearBaseFileuploadFlyoverAerialServiceMods() { + f.baseFileuploadFlyoverAerialServiceMods = nil +} + +func (f *Factory) AddBaseFileuploadFlyoverAerialServiceMod(mods ...FileuploadFlyoverAerialServiceMod) { + f.baseFileuploadFlyoverAerialServiceMods = append(f.baseFileuploadFlyoverAerialServiceMods, mods...) +} + func (f *Factory) ClearBaseFileuploadPoolMods() { f.baseFileuploadPoolMods = nil } diff --git a/db/factory/fileupload.csv.bob.go b/db/factory/fileupload.csv.bob.go index 0cf7aca2..db2872d8 100644 --- a/db/factory/fileupload.csv.bob.go +++ b/db/factory/fileupload.csv.bob.go @@ -50,9 +50,10 @@ type FileuploadCSVTemplate struct { } type fileuploadCSVR struct { - File *fileuploadCSVRFileR - CSVFileErrorCSVS []*fileuploadCSVRCSVFileErrorCSVSR - CSVFilePools []*fileuploadCSVRCSVFilePoolsR + File *fileuploadCSVRFileR + CSVFileErrorCSVS []*fileuploadCSVRCSVFileErrorCSVSR + CSVFileFlyoverAerialServices []*fileuploadCSVRCSVFileFlyoverAerialServicesR + CSVFilePools []*fileuploadCSVRCSVFilePoolsR } type fileuploadCSVRFileR struct { @@ -62,6 +63,10 @@ type fileuploadCSVRCSVFileErrorCSVSR struct { number int o *FileuploadErrorCSVTemplate } +type fileuploadCSVRCSVFileFlyoverAerialServicesR struct { + number int + o *FileuploadFlyoverAerialServiceTemplate +} type fileuploadCSVRCSVFilePoolsR struct { number int o *FileuploadPoolTemplate @@ -97,6 +102,19 @@ func (t FileuploadCSVTemplate) setModelRels(o *models.FileuploadCSV) { o.R.CSVFileErrorCSVS = rel } + if t.r.CSVFileFlyoverAerialServices != nil { + rel := models.FileuploadFlyoverAerialServiceSlice{} + for _, r := range t.r.CSVFileFlyoverAerialServices { + related := r.o.BuildMany(r.number) + for _, rel := range related { + rel.CSVFile = o.FileID // h2 + rel.R.CSVFileCSV = o + } + rel = append(rel, related...) + } + o.R.CSVFileFlyoverAerialServices = rel + } + if t.r.CSVFilePools != nil { rel := models.FileuploadPoolSlice{} for _, r := range t.r.CSVFilePools { @@ -226,6 +244,26 @@ func (o *FileuploadCSVTemplate) insertOptRels(ctx context.Context, exec bob.Exec } } + isCSVFileFlyoverAerialServicesDone, _ := fileuploadCSVRelCSVFileFlyoverAerialServicesCtx.Value(ctx) + if !isCSVFileFlyoverAerialServicesDone && o.r.CSVFileFlyoverAerialServices != nil { + ctx = fileuploadCSVRelCSVFileFlyoverAerialServicesCtx.WithValue(ctx, true) + for _, r := range o.r.CSVFileFlyoverAerialServices { + if r.o.alreadyPersisted { + m.R.CSVFileFlyoverAerialServices = append(m.R.CSVFileFlyoverAerialServices, r.o.Build()) + } else { + rel2, err := r.o.CreateMany(ctx, exec, r.number) + if err != nil { + return err + } + + err = m.AttachCSVFileFlyoverAerialServices(ctx, exec, rel2...) + if err != nil { + return err + } + } + } + } + isCSVFilePoolsDone, _ := fileuploadCSVRelCSVFilePoolsCtx.Value(ctx) if !isCSVFilePoolsDone && o.r.CSVFilePools != nil { ctx = fileuploadCSVRelCSVFilePoolsCtx.WithValue(ctx, true) @@ -233,12 +271,12 @@ func (o *FileuploadCSVTemplate) insertOptRels(ctx context.Context, exec bob.Exec if r.o.alreadyPersisted { m.R.CSVFilePools = append(m.R.CSVFilePools, r.o.Build()) } else { - rel2, err := r.o.CreateMany(ctx, exec, r.number) + rel3, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCSVFilePools(ctx, exec, rel2...) + err = m.AttachCSVFilePools(ctx, exec, rel3...) if err != nil { return err } @@ -602,6 +640,54 @@ func (m fileuploadCSVMods) WithoutCSVFileErrorCSVS() FileuploadCSVMod { }) } +func (m fileuploadCSVMods) WithCSVFileFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + o.r.CSVFileFlyoverAerialServices = []*fileuploadCSVRCSVFileFlyoverAerialServicesR{{ + number: number, + o: related, + }} + }) +} + +func (m fileuploadCSVMods) WithNewCSVFileFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.WithCSVFileFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m fileuploadCSVMods) AddCSVFileFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + o.r.CSVFileFlyoverAerialServices = append(o.r.CSVFileFlyoverAerialServices, &fileuploadCSVRCSVFileFlyoverAerialServicesR{ + number: number, + o: related, + }) + }) +} + +func (m fileuploadCSVMods) AddNewCSVFileFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.AddCSVFileFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m fileuploadCSVMods) AddExistingCSVFileFlyoverAerialServices(existingModels ...*models.FileuploadFlyoverAerialService) FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + for _, em := range existingModels { + o.r.CSVFileFlyoverAerialServices = append(o.r.CSVFileFlyoverAerialServices, &fileuploadCSVRCSVFileFlyoverAerialServicesR{ + o: o.f.FromExistingFileuploadFlyoverAerialService(em), + }) + } + }) +} + +func (m fileuploadCSVMods) WithoutCSVFileFlyoverAerialServices() FileuploadCSVMod { + return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { + o.r.CSVFileFlyoverAerialServices = nil + }) +} + func (m fileuploadCSVMods) WithCSVFilePools(number int, related *FileuploadPoolTemplate) FileuploadCSVMod { return FileuploadCSVModFunc(func(ctx context.Context, o *FileuploadCSVTemplate) { o.r.CSVFilePools = []*fileuploadCSVRCSVFilePoolsR{{ diff --git a/db/factory/fileupload.flyover_aerial_service.bob.go b/db/factory/fileupload.flyover_aerial_service.bob.go new file mode 100644 index 00000000..7745b2bd --- /dev/null +++ b/db/factory/fileupload.flyover_aerial_service.bob.go @@ -0,0 +1,903 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package factory + +import ( + "context" + "testing" + "time" + + "github.com/Gleipnir-Technology/bob" + enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + models "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/null" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/jaswdr/faker/v2" +) + +type FileuploadFlyoverAerialServiceMod interface { + Apply(context.Context, *FileuploadFlyoverAerialServiceTemplate) +} + +type FileuploadFlyoverAerialServiceModFunc func(context.Context, *FileuploadFlyoverAerialServiceTemplate) + +func (f FileuploadFlyoverAerialServiceModFunc) Apply(ctx context.Context, n *FileuploadFlyoverAerialServiceTemplate) { + f(ctx, n) +} + +type FileuploadFlyoverAerialServiceModSlice []FileuploadFlyoverAerialServiceMod + +func (mods FileuploadFlyoverAerialServiceModSlice) Apply(ctx context.Context, n *FileuploadFlyoverAerialServiceTemplate) { + for _, f := range mods { + f.Apply(ctx, n) + } +} + +// FileuploadFlyoverAerialServiceTemplate is an object representing the database table. +// all columns are optional and should be set by mods +type FileuploadFlyoverAerialServiceTemplate struct { + Committed func() bool + Condition func() enums.FileuploadPoolconditiontype + Created func() time.Time + CreatorID func() int32 + CSVFile func() int32 + Deleted func() null.Val[time.Time] + Geom func() null.Val[string] + H3cell func() null.Val[string] + ID func() int32 + OrganizationID func() int32 + + r fileuploadFlyoverAerialServiceR + f *Factory + + alreadyPersisted bool +} + +type fileuploadFlyoverAerialServiceR struct { + CreatorUser *fileuploadFlyoverAerialServiceRCreatorUserR + CSVFileCSV *fileuploadFlyoverAerialServiceRCSVFileCSVR + Organization *fileuploadFlyoverAerialServiceROrganizationR +} + +type fileuploadFlyoverAerialServiceRCreatorUserR struct { + o *UserTemplate +} +type fileuploadFlyoverAerialServiceRCSVFileCSVR struct { + o *FileuploadCSVTemplate +} +type fileuploadFlyoverAerialServiceROrganizationR struct { + o *OrganizationTemplate +} + +// Apply mods to the FileuploadFlyoverAerialServiceTemplate +func (o *FileuploadFlyoverAerialServiceTemplate) Apply(ctx context.Context, mods ...FileuploadFlyoverAerialServiceMod) { + for _, mod := range mods { + mod.Apply(ctx, o) + } +} + +// setModelRels creates and sets the relationships on *models.FileuploadFlyoverAerialService +// according to the relationships in the template. Nothing is inserted into the db +func (t FileuploadFlyoverAerialServiceTemplate) setModelRels(o *models.FileuploadFlyoverAerialService) { + if t.r.CreatorUser != nil { + rel := t.r.CreatorUser.o.Build() + rel.R.CreatorFlyoverAerialServices = append(rel.R.CreatorFlyoverAerialServices, o) + o.CreatorID = rel.ID // h2 + o.R.CreatorUser = rel + } + + if t.r.CSVFileCSV != nil { + rel := t.r.CSVFileCSV.o.Build() + rel.R.CSVFileFlyoverAerialServices = append(rel.R.CSVFileFlyoverAerialServices, o) + o.CSVFile = rel.FileID // h2 + o.R.CSVFileCSV = rel + } + + if t.r.Organization != nil { + rel := t.r.Organization.o.Build() + rel.R.FlyoverAerialServices = append(rel.R.FlyoverAerialServices, o) + o.OrganizationID = rel.ID // h2 + o.R.Organization = rel + } +} + +// BuildSetter returns an *models.FileuploadFlyoverAerialServiceSetter +// this does nothing with the relationship templates +func (o FileuploadFlyoverAerialServiceTemplate) BuildSetter() *models.FileuploadFlyoverAerialServiceSetter { + m := &models.FileuploadFlyoverAerialServiceSetter{} + + if o.Committed != nil { + val := o.Committed() + m.Committed = omit.From(val) + } + if o.Condition != nil { + val := o.Condition() + m.Condition = omit.From(val) + } + if o.Created != nil { + val := o.Created() + m.Created = omit.From(val) + } + if o.CreatorID != nil { + val := o.CreatorID() + m.CreatorID = omit.From(val) + } + if o.CSVFile != nil { + val := o.CSVFile() + m.CSVFile = omit.From(val) + } + if o.Deleted != nil { + val := o.Deleted() + m.Deleted = omitnull.FromNull(val) + } + if o.Geom != nil { + val := o.Geom() + m.Geom = omitnull.FromNull(val) + } + if o.H3cell != nil { + val := o.H3cell() + m.H3cell = omitnull.FromNull(val) + } + if o.ID != nil { + val := o.ID() + m.ID = omit.From(val) + } + if o.OrganizationID != nil { + val := o.OrganizationID() + m.OrganizationID = omit.From(val) + } + + return m +} + +// BuildManySetter returns an []*models.FileuploadFlyoverAerialServiceSetter +// this does nothing with the relationship templates +func (o FileuploadFlyoverAerialServiceTemplate) BuildManySetter(number int) []*models.FileuploadFlyoverAerialServiceSetter { + m := make([]*models.FileuploadFlyoverAerialServiceSetter, number) + + for i := range m { + m[i] = o.BuildSetter() + } + + return m +} + +// Build returns an *models.FileuploadFlyoverAerialService +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use FileuploadFlyoverAerialServiceTemplate.Create +func (o FileuploadFlyoverAerialServiceTemplate) Build() *models.FileuploadFlyoverAerialService { + m := &models.FileuploadFlyoverAerialService{} + + if o.Committed != nil { + m.Committed = o.Committed() + } + if o.Condition != nil { + m.Condition = o.Condition() + } + if o.Created != nil { + m.Created = o.Created() + } + if o.CreatorID != nil { + m.CreatorID = o.CreatorID() + } + if o.CSVFile != nil { + m.CSVFile = o.CSVFile() + } + if o.Deleted != nil { + m.Deleted = o.Deleted() + } + if o.Geom != nil { + m.Geom = o.Geom() + } + if o.H3cell != nil { + m.H3cell = o.H3cell() + } + if o.ID != nil { + m.ID = o.ID() + } + if o.OrganizationID != nil { + m.OrganizationID = o.OrganizationID() + } + + o.setModelRels(m) + + return m +} + +// BuildMany returns an models.FileuploadFlyoverAerialServiceSlice +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use FileuploadFlyoverAerialServiceTemplate.CreateMany +func (o FileuploadFlyoverAerialServiceTemplate) BuildMany(number int) models.FileuploadFlyoverAerialServiceSlice { + m := make(models.FileuploadFlyoverAerialServiceSlice, number) + + for i := range m { + m[i] = o.Build() + } + + return m +} + +func ensureCreatableFileuploadFlyoverAerialService(m *models.FileuploadFlyoverAerialServiceSetter) { + if !(m.Committed.IsValue()) { + val := random_bool(nil) + m.Committed = omit.From(val) + } + if !(m.Condition.IsValue()) { + val := random_enums_FileuploadPoolconditiontype(nil) + m.Condition = omit.From(val) + } + if !(m.Created.IsValue()) { + val := random_time_Time(nil) + m.Created = omit.From(val) + } + if !(m.CreatorID.IsValue()) { + val := random_int32(nil) + m.CreatorID = omit.From(val) + } + if !(m.CSVFile.IsValue()) { + val := random_int32(nil) + m.CSVFile = omit.From(val) + } + if !(m.OrganizationID.IsValue()) { + val := random_int32(nil) + m.OrganizationID = omit.From(val) + } +} + +// insertOptRels creates and inserts any optional the relationships on *models.FileuploadFlyoverAerialService +// according to the relationships in the template. +// any required relationship should have already exist on the model +func (o *FileuploadFlyoverAerialServiceTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.FileuploadFlyoverAerialService) error { + var err error + + return err +} + +// Create builds a fileuploadFlyoverAerialService and inserts it into the database +// Relations objects are also inserted and placed in the .R field +func (o *FileuploadFlyoverAerialServiceTemplate) Create(ctx context.Context, exec bob.Executor) (*models.FileuploadFlyoverAerialService, error) { + var err error + opt := o.BuildSetter() + ensureCreatableFileuploadFlyoverAerialService(opt) + + if o.r.CreatorUser == nil { + FileuploadFlyoverAerialServiceMods.WithNewCreatorUser().Apply(ctx, o) + } + + var rel0 *models.User + + if o.r.CreatorUser.o.alreadyPersisted { + rel0 = o.r.CreatorUser.o.Build() + } else { + rel0, err = o.r.CreatorUser.o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + opt.CreatorID = omit.From(rel0.ID) + + if o.r.CSVFileCSV == nil { + FileuploadFlyoverAerialServiceMods.WithNewCSVFileCSV().Apply(ctx, o) + } + + var rel1 *models.FileuploadCSV + + if o.r.CSVFileCSV.o.alreadyPersisted { + rel1 = o.r.CSVFileCSV.o.Build() + } else { + rel1, err = o.r.CSVFileCSV.o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + opt.CSVFile = omit.From(rel1.FileID) + + if o.r.Organization == nil { + FileuploadFlyoverAerialServiceMods.WithNewOrganization().Apply(ctx, o) + } + + var rel2 *models.Organization + + if o.r.Organization.o.alreadyPersisted { + rel2 = o.r.Organization.o.Build() + } else { + rel2, err = o.r.Organization.o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + opt.OrganizationID = omit.From(rel2.ID) + + m, err := models.FileuploadFlyoverAerialServices.Insert(opt).One(ctx, exec) + if err != nil { + return nil, err + } + + m.R.CreatorUser = rel0 + m.R.CSVFileCSV = rel1 + m.R.Organization = rel2 + + if err := o.insertOptRels(ctx, exec, m); err != nil { + return nil, err + } + return m, err +} + +// MustCreate builds a fileuploadFlyoverAerialService and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o *FileuploadFlyoverAerialServiceTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.FileuploadFlyoverAerialService { + m, err := o.Create(ctx, exec) + if err != nil { + panic(err) + } + return m +} + +// CreateOrFail builds a fileuploadFlyoverAerialService and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o *FileuploadFlyoverAerialServiceTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.FileuploadFlyoverAerialService { + tb.Helper() + m, err := o.Create(ctx, exec) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// CreateMany builds multiple fileuploadFlyoverAerialServices and inserts them into the database +// Relations objects are also inserted and placed in the .R field +func (o FileuploadFlyoverAerialServiceTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.FileuploadFlyoverAerialServiceSlice, error) { + var err error + m := make(models.FileuploadFlyoverAerialServiceSlice, number) + + for i := range m { + m[i], err = o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + return m, nil +} + +// MustCreateMany builds multiple fileuploadFlyoverAerialServices and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o FileuploadFlyoverAerialServiceTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.FileuploadFlyoverAerialServiceSlice { + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + panic(err) + } + return m +} + +// CreateManyOrFail builds multiple fileuploadFlyoverAerialServices and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o FileuploadFlyoverAerialServiceTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.FileuploadFlyoverAerialServiceSlice { + tb.Helper() + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// FileuploadFlyoverAerialService has methods that act as mods for the FileuploadFlyoverAerialServiceTemplate +var FileuploadFlyoverAerialServiceMods fileuploadFlyoverAerialServiceMods + +type fileuploadFlyoverAerialServiceMods struct{} + +func (m fileuploadFlyoverAerialServiceMods) RandomizeAllColumns(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModSlice{ + FileuploadFlyoverAerialServiceMods.RandomCommitted(f), + FileuploadFlyoverAerialServiceMods.RandomCondition(f), + FileuploadFlyoverAerialServiceMods.RandomCreated(f), + FileuploadFlyoverAerialServiceMods.RandomCreatorID(f), + FileuploadFlyoverAerialServiceMods.RandomCSVFile(f), + FileuploadFlyoverAerialServiceMods.RandomDeleted(f), + FileuploadFlyoverAerialServiceMods.RandomGeom(f), + FileuploadFlyoverAerialServiceMods.RandomH3cell(f), + FileuploadFlyoverAerialServiceMods.RandomID(f), + FileuploadFlyoverAerialServiceMods.RandomOrganizationID(f), + } +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) Committed(val bool) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Committed = func() bool { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) CommittedFunc(f func() bool) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Committed = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetCommitted() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Committed = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomCommitted(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Committed = func() bool { + return random_bool(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) Condition(val enums.FileuploadPoolconditiontype) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Condition = func() enums.FileuploadPoolconditiontype { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) ConditionFunc(f func() enums.FileuploadPoolconditiontype) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Condition = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetCondition() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Condition = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomCondition(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Condition = func() enums.FileuploadPoolconditiontype { + return random_enums_FileuploadPoolconditiontype(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) Created(val time.Time) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Created = func() time.Time { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) CreatedFunc(f func() time.Time) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Created = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetCreated() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Created = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomCreated(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Created = func() time.Time { + return random_time_Time(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) CreatorID(val int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CreatorID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) CreatorIDFunc(f func() int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CreatorID = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetCreatorID() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CreatorID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomCreatorID(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CreatorID = func() int32 { + return random_int32(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) CSVFile(val int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CSVFile = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) CSVFileFunc(f func() int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CSVFile = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetCSVFile() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CSVFile = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomCSVFile(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.CSVFile = func() int32 { + return random_int32(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) Deleted(val null.Val[time.Time]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Deleted = func() null.Val[time.Time] { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) DeletedFunc(f func() null.Val[time.Time]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Deleted = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetDeleted() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Deleted = 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 fileuploadFlyoverAerialServiceMods) RandomDeleted(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Deleted = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(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 fileuploadFlyoverAerialServiceMods) RandomDeletedNotNull(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Deleted = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(f) + return null.From(val) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) Geom(val null.Val[string]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Geom = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) GeomFunc(f func() null.Val[string]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Geom = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetGeom() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Geom = 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 fileuploadFlyoverAerialServiceMods) RandomGeom(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(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 fileuploadFlyoverAerialServiceMods) RandomGeomNotNull(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) H3cell(val null.Val[string]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.H3cell = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) H3cellFunc(f func() null.Val[string]) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.H3cell = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetH3cell() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.H3cell = 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 fileuploadFlyoverAerialServiceMods) RandomH3cell(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.H3cell = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(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 fileuploadFlyoverAerialServiceMods) RandomH3cellNotNull(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.H3cell = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) ID(val int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.ID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) IDFunc(f func() int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.ID = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetID() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.ID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomID(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.ID = func() int32 { + return random_int32(f) + } + }) +} + +// Set the model columns to this value +func (m fileuploadFlyoverAerialServiceMods) OrganizationID(val int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.OrganizationID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m fileuploadFlyoverAerialServiceMods) OrganizationIDFunc(f func() int32) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.OrganizationID = f + }) +} + +// Clear any values for the column +func (m fileuploadFlyoverAerialServiceMods) UnsetOrganizationID() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.OrganizationID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m fileuploadFlyoverAerialServiceMods) RandomOrganizationID(f *faker.Faker) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(_ context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.OrganizationID = func() int32 { + return random_int32(f) + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithParentsCascading() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + if isDone, _ := fileuploadFlyoverAerialServiceWithParentsCascadingCtx.Value(ctx); isDone { + return + } + ctx = fileuploadFlyoverAerialServiceWithParentsCascadingCtx.WithValue(ctx, true) + { + + related := o.f.NewUserWithContext(ctx, UserMods.WithParentsCascading()) + m.WithCreatorUser(related).Apply(ctx, o) + } + { + + related := o.f.NewFileuploadCSVWithContext(ctx, FileuploadCSVMods.WithParentsCascading()) + m.WithCSVFileCSV(related).Apply(ctx, o) + } + { + + related := o.f.NewOrganizationWithContext(ctx, OrganizationMods.WithParentsCascading()) + m.WithOrganization(related).Apply(ctx, o) + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithCreatorUser(rel *UserTemplate) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CreatorUser = &fileuploadFlyoverAerialServiceRCreatorUserR{ + o: rel, + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithNewCreatorUser(mods ...UserMod) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + related := o.f.NewUserWithContext(ctx, mods...) + + m.WithCreatorUser(related).Apply(ctx, o) + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithExistingCreatorUser(em *models.User) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CreatorUser = &fileuploadFlyoverAerialServiceRCreatorUserR{ + o: o.f.FromExistingUser(em), + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithoutCreatorUser() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CreatorUser = nil + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithCSVFileCSV(rel *FileuploadCSVTemplate) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CSVFileCSV = &fileuploadFlyoverAerialServiceRCSVFileCSVR{ + o: rel, + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithNewCSVFileCSV(mods ...FileuploadCSVMod) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + related := o.f.NewFileuploadCSVWithContext(ctx, mods...) + + m.WithCSVFileCSV(related).Apply(ctx, o) + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithExistingCSVFileCSV(em *models.FileuploadCSV) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CSVFileCSV = &fileuploadFlyoverAerialServiceRCSVFileCSVR{ + o: o.f.FromExistingFileuploadCSV(em), + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithoutCSVFileCSV() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.CSVFileCSV = nil + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithOrganization(rel *OrganizationTemplate) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.Organization = &fileuploadFlyoverAerialServiceROrganizationR{ + o: rel, + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithNewOrganization(mods ...OrganizationMod) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + related := o.f.NewOrganizationWithContext(ctx, mods...) + + m.WithOrganization(related).Apply(ctx, o) + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithExistingOrganization(em *models.Organization) FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.Organization = &fileuploadFlyoverAerialServiceROrganizationR{ + o: o.f.FromExistingOrganization(em), + } + }) +} + +func (m fileuploadFlyoverAerialServiceMods) WithoutOrganization() FileuploadFlyoverAerialServiceMod { + return FileuploadFlyoverAerialServiceModFunc(func(ctx context.Context, o *FileuploadFlyoverAerialServiceTemplate) { + o.r.Organization = nil + }) +} diff --git a/db/factory/organization.bob.go b/db/factory/organization.bob.go index e92fc48f..add3c91a 100644 --- a/db/factory/organization.bob.go +++ b/db/factory/organization.bob.go @@ -112,6 +112,7 @@ type organizationR struct { Zones2s []*organizationRZones2sR FieldseekerSyncs []*organizationRFieldseekerSyncsR Files []*organizationRFilesR + FlyoverAerialServices []*organizationRFlyoverAerialServicesR Pools []*organizationRPoolsR H3Aggregations []*organizationRH3AggregationsR NoteAudios []*organizationRNoteAudiosR @@ -260,6 +261,10 @@ type organizationRFilesR struct { number int o *FileuploadFileTemplate } +type organizationRFlyoverAerialServicesR struct { + number int + o *FileuploadFlyoverAerialServiceTemplate +} type organizationRPoolsR struct { number int o *FileuploadPoolTemplate @@ -749,6 +754,19 @@ func (t OrganizationTemplate) setModelRels(o *models.Organization) { o.R.Files = rel } + if t.r.FlyoverAerialServices != nil { + rel := models.FileuploadFlyoverAerialServiceSlice{} + for _, r := range t.r.FlyoverAerialServices { + related := r.o.BuildMany(r.number) + for _, rel := range related { + rel.OrganizationID = o.ID // h2 + rel.R.Organization = o + } + rel = append(rel, related...) + } + o.R.FlyoverAerialServices = rel + } + if t.r.Pools != nil { rel := models.FileuploadPoolSlice{} for _, r := range t.r.Pools { @@ -1791,6 +1809,26 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu } } + isFlyoverAerialServicesDone, _ := organizationRelFlyoverAerialServicesCtx.Value(ctx) + if !isFlyoverAerialServicesDone && o.r.FlyoverAerialServices != nil { + ctx = organizationRelFlyoverAerialServicesCtx.WithValue(ctx, true) + for _, r := range o.r.FlyoverAerialServices { + if r.o.alreadyPersisted { + m.R.FlyoverAerialServices = append(m.R.FlyoverAerialServices, r.o.Build()) + } else { + rel34, err := r.o.CreateMany(ctx, exec, r.number) + if err != nil { + return err + } + + err = m.AttachFlyoverAerialServices(ctx, exec, rel34...) + if err != nil { + return err + } + } + } + } + isPoolsDone, _ := organizationRelPoolsCtx.Value(ctx) if !isPoolsDone && o.r.Pools != nil { ctx = organizationRelPoolsCtx.WithValue(ctx, true) @@ -1798,12 +1836,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.Pools = append(m.R.Pools, r.o.Build()) } else { - rel34, err := r.o.CreateMany(ctx, exec, r.number) + rel35, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachPools(ctx, exec, rel34...) + err = m.AttachPools(ctx, exec, rel35...) if err != nil { return err } @@ -1818,12 +1856,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.H3Aggregations = append(m.R.H3Aggregations, r.o.Build()) } else { - rel35, err := r.o.CreateMany(ctx, exec, r.number) + rel36, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachH3Aggregations(ctx, exec, rel35...) + err = m.AttachH3Aggregations(ctx, exec, rel36...) if err != nil { return err } @@ -1838,12 +1876,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.NoteAudios = append(m.R.NoteAudios, r.o.Build()) } else { - rel36, err := r.o.CreateMany(ctx, exec, r.number) + rel37, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachNoteAudios(ctx, exec, rel36...) + err = m.AttachNoteAudios(ctx, exec, rel37...) if err != nil { return err } @@ -1858,12 +1896,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.NoteImages = append(m.R.NoteImages, r.o.Build()) } else { - rel37, err := r.o.CreateMany(ctx, exec, r.number) + rel38, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachNoteImages(ctx, exec, rel37...) + err = m.AttachNoteImages(ctx, exec, rel38...) if err != nil { return err } @@ -1877,12 +1915,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if o.r.ArcgisAccountAccount.o.alreadyPersisted { m.R.ArcgisAccountAccount = o.r.ArcgisAccountAccount.o.Build() } else { - var rel38 *models.ArcgisAccount - rel38, err = o.r.ArcgisAccountAccount.o.Create(ctx, exec) + var rel39 *models.ArcgisAccount + rel39, err = o.r.ArcgisAccountAccount.o.Create(ctx, exec) if err != nil { return err } - err = m.AttachArcgisAccountAccount(ctx, exec, rel38) + err = m.AttachArcgisAccountAccount(ctx, exec, rel39) if err != nil { return err } @@ -1896,12 +1934,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if o.r.FieldseekerServiceFeatureItemServiceFeature.o.alreadyPersisted { m.R.FieldseekerServiceFeatureItemServiceFeature = o.r.FieldseekerServiceFeatureItemServiceFeature.o.Build() } else { - var rel39 *models.ArcgisServiceFeature - rel39, err = o.r.FieldseekerServiceFeatureItemServiceFeature.o.Create(ctx, exec) + var rel40 *models.ArcgisServiceFeature + rel40, err = o.r.FieldseekerServiceFeatureItemServiceFeature.o.Create(ctx, exec) if err != nil { return err } - err = m.AttachFieldseekerServiceFeatureItemServiceFeature(ctx, exec, rel39) + err = m.AttachFieldseekerServiceFeatureItemServiceFeature(ctx, exec, rel40) if err != nil { return err } @@ -1916,12 +1954,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.Nuisances = append(m.R.Nuisances, r.o.Build()) } else { - rel40, err := r.o.CreateMany(ctx, exec, r.number) + rel41, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachNuisances(ctx, exec, rel40...) + err = m.AttachNuisances(ctx, exec, rel41...) if err != nil { return err } @@ -1936,12 +1974,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.PublicreportPool = append(m.R.PublicreportPool, r.o.Build()) } else { - rel41, err := r.o.CreateMany(ctx, exec, r.number) + rel42, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachPublicreportPool(ctx, exec, rel41...) + err = m.AttachPublicreportPool(ctx, exec, rel42...) if err != nil { return err } @@ -1956,12 +1994,12 @@ func (o *OrganizationTemplate) insertOptRels(ctx context.Context, exec bob.Execu if r.o.alreadyPersisted { m.R.Quicks = append(m.R.Quicks, r.o.Build()) } else { - rel42, err := r.o.CreateMany(ctx, exec, r.number) + rel43, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachQuicks(ctx, exec, rel42...) + err = m.AttachQuicks(ctx, exec, rel43...) if err != nil { return err } @@ -1976,12 +2014,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 { - rel43, err := r.o.CreateMany(ctx, exec, r.number) + rel44, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachUser(ctx, exec, rel43...) + err = m.AttachUser(ctx, exec, rel44...) if err != nil { return err } @@ -5479,6 +5517,54 @@ func (m organizationMods) WithoutFiles() OrganizationMod { }) } +func (m organizationMods) WithFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + o.r.FlyoverAerialServices = []*organizationRFlyoverAerialServicesR{{ + number: number, + o: related, + }} + }) +} + +func (m organizationMods) WithNewFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.WithFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m organizationMods) AddFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + o.r.FlyoverAerialServices = append(o.r.FlyoverAerialServices, &organizationRFlyoverAerialServicesR{ + number: number, + o: related, + }) + }) +} + +func (m organizationMods) AddNewFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.AddFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m organizationMods) AddExistingFlyoverAerialServices(existingModels ...*models.FileuploadFlyoverAerialService) OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + for _, em := range existingModels { + o.r.FlyoverAerialServices = append(o.r.FlyoverAerialServices, &organizationRFlyoverAerialServicesR{ + o: o.f.FromExistingFileuploadFlyoverAerialService(em), + }) + } + }) +} + +func (m organizationMods) WithoutFlyoverAerialServices() OrganizationMod { + return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { + o.r.FlyoverAerialServices = nil + }) +} + func (m organizationMods) WithPools(number int, related *FileuploadPoolTemplate) OrganizationMod { return OrganizationModFunc(func(ctx context.Context, o *OrganizationTemplate) { o.r.Pools = []*organizationRPoolsR{{ diff --git a/db/factory/user_.bob.go b/db/factory/user_.bob.go index 22d66a94..f4289873 100644 --- a/db/factory/user_.bob.go +++ b/db/factory/user_.bob.go @@ -63,6 +63,7 @@ type userR struct { PublicUserUser []*userRPublicUserUserR CreatorComplianceReportRequests []*userRCreatorComplianceReportRequestsR CreatorFiles []*userRCreatorFilesR + CreatorFlyoverAerialServices []*userRCreatorFlyoverAerialServicesR FileuploadPool []*userRFileuploadPoolR CreatorNoteAudios []*userRCreatorNoteAudiosR DeletorNoteAudios []*userRDeletorNoteAudiosR @@ -91,6 +92,10 @@ type userRCreatorFilesR struct { number int o *FileuploadFileTemplate } +type userRCreatorFlyoverAerialServicesR struct { + number int + o *FileuploadFlyoverAerialServiceTemplate +} type userRFileuploadPoolR struct { number int o *FileuploadPoolTemplate @@ -193,6 +198,19 @@ func (t UserTemplate) setModelRels(o *models.User) { o.R.CreatorFiles = rel } + if t.r.CreatorFlyoverAerialServices != nil { + rel := models.FileuploadFlyoverAerialServiceSlice{} + for _, r := range t.r.CreatorFlyoverAerialServices { + related := r.o.BuildMany(r.number) + for _, rel := range related { + rel.CreatorID = o.ID // h2 + rel.R.CreatorUser = o + } + rel = append(rel, related...) + } + o.R.CreatorFlyoverAerialServices = rel + } + if t.r.FileuploadPool != nil { rel := models.FileuploadPoolSlice{} for _, r := range t.r.FileuploadPool { @@ -568,6 +586,26 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * } } + isCreatorFlyoverAerialServicesDone, _ := userRelCreatorFlyoverAerialServicesCtx.Value(ctx) + if !isCreatorFlyoverAerialServicesDone && o.r.CreatorFlyoverAerialServices != nil { + ctx = userRelCreatorFlyoverAerialServicesCtx.WithValue(ctx, true) + for _, r := range o.r.CreatorFlyoverAerialServices { + if r.o.alreadyPersisted { + m.R.CreatorFlyoverAerialServices = append(m.R.CreatorFlyoverAerialServices, r.o.Build()) + } else { + rel4, err := r.o.CreateMany(ctx, exec, r.number) + if err != nil { + return err + } + + err = m.AttachCreatorFlyoverAerialServices(ctx, exec, rel4...) + if err != nil { + return err + } + } + } + } + isFileuploadPoolDone, _ := userRelFileuploadPoolCtx.Value(ctx) if !isFileuploadPoolDone && o.r.FileuploadPool != nil { ctx = userRelFileuploadPoolCtx.WithValue(ctx, true) @@ -575,12 +613,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.FileuploadPool = append(m.R.FileuploadPool, r.o.Build()) } else { - rel4, err := r.o.CreateMany(ctx, exec, r.number) + rel5, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachFileuploadPool(ctx, exec, rel4...) + err = m.AttachFileuploadPool(ctx, exec, rel5...) if err != nil { return err } @@ -595,12 +633,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.CreatorNoteAudios = append(m.R.CreatorNoteAudios, r.o.Build()) } else { - rel5, err := r.o.CreateMany(ctx, exec, r.number) + rel6, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCreatorNoteAudios(ctx, exec, rel5...) + err = m.AttachCreatorNoteAudios(ctx, exec, rel6...) if err != nil { return err } @@ -615,12 +653,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.DeletorNoteAudios = append(m.R.DeletorNoteAudios, r.o.Build()) } else { - rel6, err := r.o.CreateMany(ctx, exec, r.number) + rel7, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachDeletorNoteAudios(ctx, exec, rel6...) + err = m.AttachDeletorNoteAudios(ctx, exec, rel7...) if err != nil { return err } @@ -635,12 +673,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.CreatorNoteImages = append(m.R.CreatorNoteImages, r.o.Build()) } else { - rel7, err := r.o.CreateMany(ctx, exec, r.number) + rel8, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCreatorNoteImages(ctx, exec, rel7...) + err = m.AttachCreatorNoteImages(ctx, exec, rel8...) if err != nil { return err } @@ -655,12 +693,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.DeletorNoteImages = append(m.R.DeletorNoteImages, r.o.Build()) } else { - rel8, err := r.o.CreateMany(ctx, exec, r.number) + rel9, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachDeletorNoteImages(ctx, exec, rel8...) + err = m.AttachDeletorNoteImages(ctx, exec, rel9...) if err != nil { return err } @@ -675,12 +713,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.UserNotifications = append(m.R.UserNotifications, r.o.Build()) } else { - rel9, err := r.o.CreateMany(ctx, exec, r.number) + rel10, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachUserNotifications(ctx, exec, rel9...) + err = m.AttachUserNotifications(ctx, exec, rel10...) if err != nil { return err } @@ -695,12 +733,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.CreatorPools = append(m.R.CreatorPools, r.o.Build()) } else { - rel10, err := r.o.CreateMany(ctx, exec, r.number) + rel11, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCreatorPools(ctx, exec, rel10...) + err = m.AttachCreatorPools(ctx, exec, rel11...) if err != nil { return err } @@ -715,12 +753,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.CreatorResidents = append(m.R.CreatorResidents, r.o.Build()) } else { - rel11, err := r.o.CreateMany(ctx, exec, r.number) + rel12, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCreatorResidents(ctx, exec, rel11...) + err = m.AttachCreatorResidents(ctx, exec, rel12...) if err != nil { return err } @@ -735,12 +773,12 @@ func (o *UserTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m * if r.o.alreadyPersisted { m.R.CreatorSites = append(m.R.CreatorSites, r.o.Build()) } else { - rel12, err := r.o.CreateMany(ctx, exec, r.number) + rel13, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachCreatorSites(ctx, exec, rel12...) + err = m.AttachCreatorSites(ctx, exec, rel13...) if err != nil { return err } @@ -762,25 +800,25 @@ func (o *UserTemplate) Create(ctx context.Context, exec bob.Executor) (*models.U UserMods.WithNewOrganization().Apply(ctx, o) } - var rel13 *models.Organization + var rel14 *models.Organization if o.r.Organization.o.alreadyPersisted { - rel13 = o.r.Organization.o.Build() + rel14 = o.r.Organization.o.Build() } else { - rel13, err = o.r.Organization.o.Create(ctx, exec) + rel14, err = o.r.Organization.o.Create(ctx, exec) if err != nil { return nil, err } } - opt.OrganizationID = omit.From(rel13.ID) + opt.OrganizationID = omit.From(rel14.ID) m, err := models.Users.Insert(opt).One(ctx, exec) if err != nil { return nil, err } - m.R.Organization = rel13 + m.R.Organization = rel14 if err := o.insertOptRels(ctx, exec, m); err != nil { return nil, err @@ -1646,6 +1684,54 @@ func (m userMods) WithoutCreatorFiles() UserMod { }) } +func (m userMods) WithCreatorFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + o.r.CreatorFlyoverAerialServices = []*userRCreatorFlyoverAerialServicesR{{ + number: number, + o: related, + }} + }) +} + +func (m userMods) WithNewCreatorFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.WithCreatorFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m userMods) AddCreatorFlyoverAerialServices(number int, related *FileuploadFlyoverAerialServiceTemplate) UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + o.r.CreatorFlyoverAerialServices = append(o.r.CreatorFlyoverAerialServices, &userRCreatorFlyoverAerialServicesR{ + number: number, + o: related, + }) + }) +} + +func (m userMods) AddNewCreatorFlyoverAerialServices(number int, mods ...FileuploadFlyoverAerialServiceMod) UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + related := o.f.NewFileuploadFlyoverAerialServiceWithContext(ctx, mods...) + m.AddCreatorFlyoverAerialServices(number, related).Apply(ctx, o) + }) +} + +func (m userMods) AddExistingCreatorFlyoverAerialServices(existingModels ...*models.FileuploadFlyoverAerialService) UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + for _, em := range existingModels { + o.r.CreatorFlyoverAerialServices = append(o.r.CreatorFlyoverAerialServices, &userRCreatorFlyoverAerialServicesR{ + o: o.f.FromExistingFileuploadFlyoverAerialService(em), + }) + } + }) +} + +func (m userMods) WithoutCreatorFlyoverAerialServices() UserMod { + return UserModFunc(func(ctx context.Context, o *UserTemplate) { + o.r.CreatorFlyoverAerialServices = nil + }) +} + func (m userMods) WithFileuploadPool(number int, related *FileuploadPoolTemplate) UserMod { return UserModFunc(func(ctx context.Context, o *UserTemplate) { o.r.FileuploadPool = []*userRFileuploadPoolR{{ diff --git a/db/migrations/00074_fileupload_pool_aerial_services.sql b/db/migrations/00074_fileupload_pool_aerial_services.sql new file mode 100644 index 00000000..a9e96361 --- /dev/null +++ b/db/migrations/00074_fileupload_pool_aerial_services.sql @@ -0,0 +1,18 @@ +-- +goose Up +ALTER TYPE fileupload.CSVType ADD VALUE 'Flyover' AFTER 'PoolList'; +CREATE TABLE fileupload.flyover_aerial_service ( + committed BOOLEAN NOT NULL, -- Whether or not its just proposed before a CSV file is committed + condition fileupload.PoolConditionType NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + creator_id INTEGER REFERENCES user_(id) NOT NULL, + csv_file INTEGER REFERENCES fileupload.csv(file_id) NOT NULL, + deleted TIMESTAMP WITHOUT TIME ZONE, + geom geometry(Point, 4326), + h3cell h3index, + id SERIAL, + organization_id INTEGER REFERENCES organization(id) NOT NULL, + PRIMARY KEY (id) +); +-- +goose Down +DROP TABLE fileupload.flyover_aerial_services; +ALTER TYPE fileupload.CSVType DROP VALUE 'Flyover'; diff --git a/db/migrations/00075_address_parcel_geom_index.sql b/db/migrations/00075_address_parcel_geom_index.sql new file mode 100644 index 00000000..5d32c049 --- /dev/null +++ b/db/migrations/00075_address_parcel_geom_index.sql @@ -0,0 +1,3 @@ +-- +goose Up +CREATE INDEX idx_address_geom ON address USING GIST (geom); +CREATE INDEX idx_parcel_geometry ON parcel USING GIST (geometry); diff --git a/db/migrations/00076_func_gen_alpha_code.sql b/db/migrations/00076_func_gen_alpha_code.sql new file mode 100644 index 00000000..701e9759 --- /dev/null +++ b/db/migrations/00076_func_gen_alpha_code.sql @@ -0,0 +1,16 @@ +-- +goose Up +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION generate_alphanumeric_code(code_length INTEGER DEFAULT 8) +RETURNS TEXT AS $$ +DECLARE + chars TEXT := 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; + result TEXT := ''; + i INTEGER; +BEGIN + FOR i IN 1..code_length LOOP + result := result || substr(chars, floor(random() * length(chars) + 1)::INTEGER, 1); + END LOOP; + RETURN result; +END; +$$ LANGUAGE plpgsql; +-- +goose StatementEnd diff --git a/db/models/bob_joins.bob.go b/db/models/bob_joins.bob.go index 32de2dbc..acf2abdc 100644 --- a/db/models/bob_joins.bob.go +++ b/db/models/bob_joins.bob.go @@ -84,6 +84,7 @@ type joins[Q dialect.Joinable] struct { FileuploadErrorCSVS joinSet[fileuploadErrorCSVJoins[Q]] FileuploadErrorFiles joinSet[fileuploadErrorFileJoins[Q]] FileuploadFiles joinSet[fileuploadFileJoins[Q]] + FileuploadFlyoverAerialServices joinSet[fileuploadFlyoverAerialServiceJoins[Q]] FileuploadPools joinSet[fileuploadPoolJoins[Q]] H3Aggregations joinSet[h3AggregationJoins[Q]] NoteAudios joinSet[noteAudioJoins[Q]] @@ -177,6 +178,7 @@ func getJoins[Q dialect.Joinable]() joins[Q] { FileuploadErrorCSVS: buildJoinSet[fileuploadErrorCSVJoins[Q]](FileuploadErrorCSVS.Columns, buildFileuploadErrorCSVJoins), FileuploadErrorFiles: buildJoinSet[fileuploadErrorFileJoins[Q]](FileuploadErrorFiles.Columns, buildFileuploadErrorFileJoins), FileuploadFiles: buildJoinSet[fileuploadFileJoins[Q]](FileuploadFiles.Columns, buildFileuploadFileJoins), + FileuploadFlyoverAerialServices: buildJoinSet[fileuploadFlyoverAerialServiceJoins[Q]](FileuploadFlyoverAerialServices.Columns, buildFileuploadFlyoverAerialServiceJoins), FileuploadPools: buildJoinSet[fileuploadPoolJoins[Q]](FileuploadPools.Columns, buildFileuploadPoolJoins), H3Aggregations: buildJoinSet[h3AggregationJoins[Q]](H3Aggregations.Columns, buildH3AggregationJoins), NoteAudios: buildJoinSet[noteAudioJoins[Q]](NoteAudios.Columns, buildNoteAudioJoins), diff --git a/db/models/bob_loaders.bob.go b/db/models/bob_loaders.bob.go index fd26aa43..1e691eb5 100644 --- a/db/models/bob_loaders.bob.go +++ b/db/models/bob_loaders.bob.go @@ -69,6 +69,7 @@ type preloaders struct { FileuploadErrorCSV fileuploadErrorCSVPreloader FileuploadErrorFile fileuploadErrorFilePreloader FileuploadFile fileuploadFilePreloader + FileuploadFlyoverAerialService fileuploadFlyoverAerialServicePreloader FileuploadPool fileuploadPoolPreloader H3Aggregation h3AggregationPreloader NoteAudio noteAudioPreloader @@ -154,6 +155,7 @@ func getPreloaders() preloaders { FileuploadErrorCSV: buildFileuploadErrorCSVPreloader(), FileuploadErrorFile: buildFileuploadErrorFilePreloader(), FileuploadFile: buildFileuploadFilePreloader(), + FileuploadFlyoverAerialService: buildFileuploadFlyoverAerialServicePreloader(), FileuploadPool: buildFileuploadPoolPreloader(), H3Aggregation: buildH3AggregationPreloader(), NoteAudio: buildNoteAudioPreloader(), @@ -245,6 +247,7 @@ type thenLoaders[Q orm.Loadable] struct { FileuploadErrorCSV fileuploadErrorCSVThenLoader[Q] FileuploadErrorFile fileuploadErrorFileThenLoader[Q] FileuploadFile fileuploadFileThenLoader[Q] + FileuploadFlyoverAerialService fileuploadFlyoverAerialServiceThenLoader[Q] FileuploadPool fileuploadPoolThenLoader[Q] H3Aggregation h3AggregationThenLoader[Q] NoteAudio noteAudioThenLoader[Q] @@ -330,6 +333,7 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] { FileuploadErrorCSV: buildFileuploadErrorCSVThenLoader[Q](), FileuploadErrorFile: buildFileuploadErrorFileThenLoader[Q](), FileuploadFile: buildFileuploadFileThenLoader[Q](), + FileuploadFlyoverAerialService: buildFileuploadFlyoverAerialServiceThenLoader[Q](), FileuploadPool: buildFileuploadPoolThenLoader[Q](), H3Aggregation: buildH3AggregationThenLoader[Q](), NoteAudio: buildNoteAudioThenLoader[Q](), diff --git a/db/models/bob_where.bob.go b/db/models/bob_where.bob.go index 0312394e..fd25e29d 100644 --- a/db/models/bob_where.bob.go +++ b/db/models/bob_where.bob.go @@ -70,6 +70,7 @@ func Where[Q psql.Filterable]() struct { FileuploadErrorCSVS fileuploadErrorCSVWhere[Q] FileuploadErrorFiles fileuploadErrorFileWhere[Q] FileuploadFiles fileuploadFileWhere[Q] + FileuploadFlyoverAerialServices fileuploadFlyoverAerialServiceWhere[Q] FileuploadPools fileuploadPoolWhere[Q] GeographyColumns geographyColumnWhere[Q] GeometryColumns geometryColumnWhere[Q] @@ -162,6 +163,7 @@ func Where[Q psql.Filterable]() struct { FileuploadErrorCSVS fileuploadErrorCSVWhere[Q] FileuploadErrorFiles fileuploadErrorFileWhere[Q] FileuploadFiles fileuploadFileWhere[Q] + FileuploadFlyoverAerialServices fileuploadFlyoverAerialServiceWhere[Q] FileuploadPools fileuploadPoolWhere[Q] GeographyColumns geographyColumnWhere[Q] GeometryColumns geometryColumnWhere[Q] @@ -253,6 +255,7 @@ func Where[Q psql.Filterable]() struct { FileuploadErrorCSVS: buildFileuploadErrorCSVWhere[Q](FileuploadErrorCSVS.Columns), FileuploadErrorFiles: buildFileuploadErrorFileWhere[Q](FileuploadErrorFiles.Columns), FileuploadFiles: buildFileuploadFileWhere[Q](FileuploadFiles.Columns), + FileuploadFlyoverAerialServices: buildFileuploadFlyoverAerialServiceWhere[Q](FileuploadFlyoverAerialServices.Columns), FileuploadPools: buildFileuploadPoolWhere[Q](FileuploadPools.Columns), GeographyColumns: buildGeographyColumnWhere[Q](GeographyColumns.Columns), GeometryColumns: buildGeometryColumnWhere[Q](GeometryColumns.Columns), diff --git a/db/models/fileupload.csv.bob.go b/db/models/fileupload.csv.bob.go index 5b1f151d..7adf77fd 100644 --- a/db/models/fileupload.csv.bob.go +++ b/db/models/fileupload.csv.bob.go @@ -49,9 +49,10 @@ type FileuploadCSVSQuery = *psql.ViewQuery[*FileuploadCSV, FileuploadCSVSlice] // fileuploadCSVR is where relationships are stored. type fileuploadCSVR struct { - File *FileuploadFile // fileupload.csv.csv_file_id_fkey - CSVFileErrorCSVS FileuploadErrorCSVSlice // fileupload.error_csv.error_csv_csv_file_id_fkey - CSVFilePools FileuploadPoolSlice // fileupload.pool.pool_csv_file_fkey + File *FileuploadFile // fileupload.csv.csv_file_id_fkey + CSVFileErrorCSVS FileuploadErrorCSVSlice // fileupload.error_csv.error_csv_csv_file_id_fkey + CSVFileFlyoverAerialServices FileuploadFlyoverAerialServiceSlice // fileupload.flyover_aerial_service.flyover_aerial_service_csv_file_fkey + CSVFilePools FileuploadPoolSlice // fileupload.pool.pool_csv_file_fkey } func buildFileuploadCSVColumns(alias string) fileuploadCSVColumns { @@ -470,6 +471,30 @@ func (os FileuploadCSVSlice) CSVFileErrorCSVS(mods ...bob.Mod[*dialect.SelectQue )...) } +// CSVFileFlyoverAerialServices starts a query for related objects on fileupload.flyover_aerial_service +func (o *FileuploadCSV) CSVFileFlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(FileuploadFlyoverAerialServices.Columns.CSVFile.EQ(psql.Arg(o.FileID))), + )...) +} + +func (os FileuploadCSVSlice) CSVFileFlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + pkFileID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkFileID = append(pkFileID, o.FileID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkFileID), "integer[]")), + )) + + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(psql.Group(FileuploadFlyoverAerialServices.Columns.CSVFile).OP("IN", PKArgExpr)), + )...) +} + // CSVFilePools starts a query for related objects on fileupload.pool func (o *FileuploadCSV) CSVFilePools(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadPoolsQuery { return FileuploadPools.Query(append(mods, @@ -610,6 +635,74 @@ func (fileuploadCSV0 *FileuploadCSV) AttachCSVFileErrorCSVS(ctx context.Context, return nil } +func insertFileuploadCSVCSVFileFlyoverAerialServices0(ctx context.Context, exec bob.Executor, fileuploadFlyoverAerialServices1 []*FileuploadFlyoverAerialServiceSetter, fileuploadCSV0 *FileuploadCSV) (FileuploadFlyoverAerialServiceSlice, error) { + for i := range fileuploadFlyoverAerialServices1 { + fileuploadFlyoverAerialServices1[i].CSVFile = omit.From(fileuploadCSV0.FileID) + } + + ret, err := FileuploadFlyoverAerialServices.Insert(bob.ToMods(fileuploadFlyoverAerialServices1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertFileuploadCSVCSVFileFlyoverAerialServices0: %w", err) + } + + return ret, nil +} + +func attachFileuploadCSVCSVFileFlyoverAerialServices0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialServices1 FileuploadFlyoverAerialServiceSlice, fileuploadCSV0 *FileuploadCSV) (FileuploadFlyoverAerialServiceSlice, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + CSVFile: omit.From(fileuploadCSV0.FileID), + } + + err := fileuploadFlyoverAerialServices1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachFileuploadCSVCSVFileFlyoverAerialServices0: %w", err) + } + + return fileuploadFlyoverAerialServices1, nil +} + +func (fileuploadCSV0 *FileuploadCSV) InsertCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialServiceSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + fileuploadFlyoverAerialServices1, err := insertFileuploadCSVCSVFileFlyoverAerialServices0(ctx, exec, related, fileuploadCSV0) + if err != nil { + return err + } + + fileuploadCSV0.R.CSVFileFlyoverAerialServices = append(fileuploadCSV0.R.CSVFileFlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range fileuploadFlyoverAerialServices1 { + rel.R.CSVFileCSV = fileuploadCSV0 + } + return nil +} + +func (fileuploadCSV0 *FileuploadCSV) AttachCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialService) error { + if len(related) == 0 { + return nil + } + + var err error + fileuploadFlyoverAerialServices1 := FileuploadFlyoverAerialServiceSlice(related) + + _, err = attachFileuploadCSVCSVFileFlyoverAerialServices0(ctx, exec, len(related), fileuploadFlyoverAerialServices1, fileuploadCSV0) + if err != nil { + return err + } + + fileuploadCSV0.R.CSVFileFlyoverAerialServices = append(fileuploadCSV0.R.CSVFileFlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range related { + rel.R.CSVFileCSV = fileuploadCSV0 + } + + return nil +} + func insertFileuploadCSVCSVFilePools0(ctx context.Context, exec bob.Executor, fileuploadPools1 []*FileuploadPoolSetter, fileuploadCSV0 *FileuploadCSV) (FileuploadPoolSlice, error) { for i := range fileuploadPools1 { fileuploadPools1[i].CSVFile = omit.From(fileuploadCSV0.FileID) @@ -724,6 +817,20 @@ func (o *FileuploadCSV) Preload(name string, retrieved any) error { o.R.CSVFileErrorCSVS = rels + for _, rel := range rels { + if rel != nil { + rel.R.CSVFileCSV = o + } + } + return nil + case "CSVFileFlyoverAerialServices": + rels, ok := retrieved.(FileuploadFlyoverAerialServiceSlice) + if !ok { + return fmt.Errorf("fileuploadCSV cannot load %T as %q", retrieved, name) + } + + o.R.CSVFileFlyoverAerialServices = rels + for _, rel := range rels { if rel != nil { rel.R.CSVFileCSV = o @@ -772,9 +879,10 @@ func buildFileuploadCSVPreloader() fileuploadCSVPreloader { } type fileuploadCSVThenLoader[Q orm.Loadable] struct { - File func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] - CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] - CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + File func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFileFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildFileuploadCSVThenLoader[Q orm.Loadable]() fileuploadCSVThenLoader[Q] { @@ -784,6 +892,9 @@ func buildFileuploadCSVThenLoader[Q orm.Loadable]() fileuploadCSVThenLoader[Q] { type CSVFileErrorCSVSLoadInterface interface { LoadCSVFileErrorCSVS(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type CSVFileFlyoverAerialServicesLoadInterface interface { + LoadCSVFileFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type CSVFilePoolsLoadInterface interface { LoadCSVFilePools(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -801,6 +912,12 @@ func buildFileuploadCSVThenLoader[Q orm.Loadable]() fileuploadCSVThenLoader[Q] { return retrieved.LoadCSVFileErrorCSVS(ctx, exec, mods...) }, ), + CSVFileFlyoverAerialServices: thenLoadBuilder[Q]( + "CSVFileFlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved CSVFileFlyoverAerialServicesLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCSVFileFlyoverAerialServices(ctx, exec, mods...) + }, + ), CSVFilePools: thenLoadBuilder[Q]( "CSVFilePools", func(ctx context.Context, exec bob.Executor, retrieved CSVFilePoolsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -923,6 +1040,67 @@ func (os FileuploadCSVSlice) LoadCSVFileErrorCSVS(ctx context.Context, exec bob. return nil } +// LoadCSVFileFlyoverAerialServices loads the fileuploadCSV's CSVFileFlyoverAerialServices into the .R struct +func (o *FileuploadCSV) LoadCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.CSVFileFlyoverAerialServices = nil + + related, err := o.CSVFileFlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.CSVFileCSV = o + } + + o.R.CSVFileFlyoverAerialServices = related + return nil +} + +// LoadCSVFileFlyoverAerialServices loads the fileuploadCSV's CSVFileFlyoverAerialServices into the .R struct +func (os FileuploadCSVSlice) LoadCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + fileuploadFlyoverAerialServices, err := os.CSVFileFlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.CSVFileFlyoverAerialServices = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range fileuploadFlyoverAerialServices { + + if !(o.FileID == rel.CSVFile) { + continue + } + + rel.R.CSVFileCSV = o + + o.R.CSVFileFlyoverAerialServices = append(o.R.CSVFileFlyoverAerialServices, rel) + } + } + + return nil +} + // LoadCSVFilePools loads the fileuploadCSV's CSVFilePools into the .R struct func (o *FileuploadCSV) LoadCSVFilePools(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -986,8 +1164,9 @@ func (os FileuploadCSVSlice) LoadCSVFilePools(ctx context.Context, exec bob.Exec // fileuploadCSVC is where relationship counts are stored. type fileuploadCSVC struct { - CSVFileErrorCSVS *int64 - CSVFilePools *int64 + CSVFileErrorCSVS *int64 + CSVFileFlyoverAerialServices *int64 + CSVFilePools *int64 } // PreloadCount sets a count in the C struct by name @@ -999,6 +1178,8 @@ func (o *FileuploadCSV) PreloadCount(name string, count int64) error { switch name { case "CSVFileErrorCSVS": o.C.CSVFileErrorCSVS = &count + case "CSVFileFlyoverAerialServices": + o.C.CSVFileFlyoverAerialServices = &count case "CSVFilePools": o.C.CSVFilePools = &count } @@ -1006,8 +1187,9 @@ func (o *FileuploadCSV) PreloadCount(name string, count int64) error { } type fileuploadCSVCountPreloader struct { - CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader - CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader + CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader + CSVFileFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader + CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader } func buildFileuploadCSVCountPreloader() fileuploadCSVCountPreloader { @@ -1029,6 +1211,23 @@ func buildFileuploadCSVCountPreloader() fileuploadCSVCountPreloader { return psql.Group(psql.Select(subqueryMods...).Expression) }) }, + CSVFileFlyoverAerialServices: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { + return countPreloader[*FileuploadCSV]("CSVFileFlyoverAerialServices", func(parent string) bob.Expression { + // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) + if parent == "" { + parent = FileuploadCSVS.Alias() + } + + subqueryMods := []bob.Mod[*dialect.SelectQuery]{ + sm.Columns(psql.Raw("count(*)")), + + sm.From(FileuploadFlyoverAerialServices.Name()), + sm.Where(psql.Quote(FileuploadFlyoverAerialServices.Alias(), "csv_file").EQ(psql.Quote(parent, "file_id"))), + } + subqueryMods = append(subqueryMods, mods...) + return psql.Group(psql.Select(subqueryMods...).Expression) + }) + }, CSVFilePools: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { return countPreloader[*FileuploadCSV]("CSVFilePools", func(parent string) bob.Expression { // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) @@ -1050,14 +1249,18 @@ func buildFileuploadCSVCountPreloader() fileuploadCSVCountPreloader { } type fileuploadCSVCountThenLoader[Q orm.Loadable] struct { - CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] - CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFileErrorCSVS func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFileFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFilePools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildFileuploadCSVCountThenLoader[Q orm.Loadable]() fileuploadCSVCountThenLoader[Q] { type CSVFileErrorCSVSCountInterface interface { LoadCountCSVFileErrorCSVS(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type CSVFileFlyoverAerialServicesCountInterface interface { + LoadCountCSVFileFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type CSVFilePoolsCountInterface interface { LoadCountCSVFilePools(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -1069,6 +1272,12 @@ func buildFileuploadCSVCountThenLoader[Q orm.Loadable]() fileuploadCSVCountThenL return retrieved.LoadCountCSVFileErrorCSVS(ctx, exec, mods...) }, ), + CSVFileFlyoverAerialServices: countThenLoadBuilder[Q]( + "CSVFileFlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved CSVFileFlyoverAerialServicesCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCountCSVFileFlyoverAerialServices(ctx, exec, mods...) + }, + ), CSVFilePools: countThenLoadBuilder[Q]( "CSVFilePools", func(ctx context.Context, exec bob.Executor, retrieved CSVFilePoolsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -1108,6 +1317,36 @@ func (os FileuploadCSVSlice) LoadCountCSVFileErrorCSVS(ctx context.Context, exec return nil } +// LoadCountCSVFileFlyoverAerialServices loads the count of CSVFileFlyoverAerialServices into the C struct +func (o *FileuploadCSV) LoadCountCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + count, err := o.CSVFileFlyoverAerialServices(mods...).Count(ctx, exec) + if err != nil { + return err + } + + o.C.CSVFileFlyoverAerialServices = &count + return nil +} + +// LoadCountCSVFileFlyoverAerialServices loads the count of CSVFileFlyoverAerialServices for a slice +func (os FileuploadCSVSlice) LoadCountCSVFileFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + for _, o := range os { + if err := o.LoadCountCSVFileFlyoverAerialServices(ctx, exec, mods...); err != nil { + return err + } + } + + return nil +} + // LoadCountCSVFilePools loads the count of CSVFilePools into the C struct func (o *FileuploadCSV) LoadCountCSVFilePools(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -1139,10 +1378,11 @@ func (os FileuploadCSVSlice) LoadCountCSVFilePools(ctx context.Context, exec bob } type fileuploadCSVJoins[Q dialect.Joinable] struct { - typ string - File modAs[Q, fileuploadFileColumns] - CSVFileErrorCSVS modAs[Q, fileuploadErrorCSVColumns] - CSVFilePools modAs[Q, fileuploadPoolColumns] + typ string + File modAs[Q, fileuploadFileColumns] + CSVFileErrorCSVS modAs[Q, fileuploadErrorCSVColumns] + CSVFileFlyoverAerialServices modAs[Q, fileuploadFlyoverAerialServiceColumns] + CSVFilePools modAs[Q, fileuploadPoolColumns] } func (j fileuploadCSVJoins[Q]) aliasedAs(alias string) fileuploadCSVJoins[Q] { @@ -1180,6 +1420,20 @@ func buildFileuploadCSVJoins[Q dialect.Joinable](cols fileuploadCSVColumns, typ return mods }, }, + CSVFileFlyoverAerialServices: modAs[Q, fileuploadFlyoverAerialServiceColumns]{ + c: FileuploadFlyoverAerialServices.Columns, + f: func(to fileuploadFlyoverAerialServiceColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, FileuploadFlyoverAerialServices.Name().As(to.Alias())).On( + to.CSVFile.EQ(cols.FileID), + )) + } + + return mods + }, + }, CSVFilePools: modAs[Q, fileuploadPoolColumns]{ c: FileuploadPools.Columns, f: func(to fileuploadPoolColumns) bob.Mod[Q] { diff --git a/db/models/fileupload.flyover_aerial_service.bob.go b/db/models/fileupload.flyover_aerial_service.bob.go new file mode 100644 index 00000000..91359dd9 --- /dev/null +++ b/db/models/fileupload.flyover_aerial_service.bob.go @@ -0,0 +1,1158 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "fmt" + "io" + "time" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/dialect" + "github.com/Gleipnir-Technology/bob/dialect/psql/dm" + "github.com/Gleipnir-Technology/bob/dialect/psql/sm" + "github.com/Gleipnir-Technology/bob/dialect/psql/um" + "github.com/Gleipnir-Technology/bob/expr" + "github.com/Gleipnir-Technology/bob/mods" + "github.com/Gleipnir-Technology/bob/orm" + "github.com/Gleipnir-Technology/bob/types/pgtypes" + enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/aarondl/opt/null" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" +) + +// FileuploadFlyoverAerialService is an object representing the database table. +type FileuploadFlyoverAerialService struct { + Committed bool `db:"committed" ` + Condition enums.FileuploadPoolconditiontype `db:"condition" ` + Created time.Time `db:"created" ` + CreatorID int32 `db:"creator_id" ` + CSVFile int32 `db:"csv_file" ` + Deleted null.Val[time.Time] `db:"deleted" ` + Geom null.Val[string] `db:"geom" ` + H3cell null.Val[string] `db:"h3cell" ` + ID int32 `db:"id,pk" ` + OrganizationID int32 `db:"organization_id" ` + + R fileuploadFlyoverAerialServiceR `db:"-" ` +} + +// FileuploadFlyoverAerialServiceSlice is an alias for a slice of pointers to FileuploadFlyoverAerialService. +// This should almost always be used instead of []*FileuploadFlyoverAerialService. +type FileuploadFlyoverAerialServiceSlice []*FileuploadFlyoverAerialService + +// FileuploadFlyoverAerialServices contains methods to work with the flyover_aerial_service table +var FileuploadFlyoverAerialServices = psql.NewTablex[*FileuploadFlyoverAerialService, FileuploadFlyoverAerialServiceSlice, *FileuploadFlyoverAerialServiceSetter]("fileupload", "flyover_aerial_service", buildFileuploadFlyoverAerialServiceColumns("fileupload.flyover_aerial_service")) + +// FileuploadFlyoverAerialServicesQuery is a query on the flyover_aerial_service table +type FileuploadFlyoverAerialServicesQuery = *psql.ViewQuery[*FileuploadFlyoverAerialService, FileuploadFlyoverAerialServiceSlice] + +// fileuploadFlyoverAerialServiceR is where relationships are stored. +type fileuploadFlyoverAerialServiceR struct { + CreatorUser *User // fileupload.flyover_aerial_service.flyover_aerial_service_creator_id_fkey + CSVFileCSV *FileuploadCSV // fileupload.flyover_aerial_service.flyover_aerial_service_csv_file_fkey + Organization *Organization // fileupload.flyover_aerial_service.flyover_aerial_service_organization_id_fkey +} + +func buildFileuploadFlyoverAerialServiceColumns(alias string) fileuploadFlyoverAerialServiceColumns { + return fileuploadFlyoverAerialServiceColumns{ + ColumnsExpr: expr.NewColumnsExpr( + "committed", "condition", "created", "creator_id", "csv_file", "deleted", "geom", "h3cell", "id", "organization_id", + ).WithParent("fileupload.flyover_aerial_service"), + tableAlias: alias, + Committed: psql.Quote(alias, "committed"), + Condition: psql.Quote(alias, "condition"), + Created: psql.Quote(alias, "created"), + CreatorID: psql.Quote(alias, "creator_id"), + CSVFile: psql.Quote(alias, "csv_file"), + Deleted: psql.Quote(alias, "deleted"), + Geom: psql.Quote(alias, "geom"), + H3cell: psql.Quote(alias, "h3cell"), + ID: psql.Quote(alias, "id"), + OrganizationID: psql.Quote(alias, "organization_id"), + } +} + +type fileuploadFlyoverAerialServiceColumns struct { + expr.ColumnsExpr + tableAlias string + Committed psql.Expression + Condition psql.Expression + Created psql.Expression + CreatorID psql.Expression + CSVFile psql.Expression + Deleted psql.Expression + Geom psql.Expression + H3cell psql.Expression + ID psql.Expression + OrganizationID psql.Expression +} + +func (c fileuploadFlyoverAerialServiceColumns) Alias() string { + return c.tableAlias +} + +func (fileuploadFlyoverAerialServiceColumns) AliasedAs(alias string) fileuploadFlyoverAerialServiceColumns { + return buildFileuploadFlyoverAerialServiceColumns(alias) +} + +// FileuploadFlyoverAerialServiceSetter is used for insert/upsert/update operations +// All values are optional, and do not have to be set +// Generated columns are not included +type FileuploadFlyoverAerialServiceSetter struct { + Committed omit.Val[bool] `db:"committed" ` + Condition omit.Val[enums.FileuploadPoolconditiontype] `db:"condition" ` + Created omit.Val[time.Time] `db:"created" ` + CreatorID omit.Val[int32] `db:"creator_id" ` + CSVFile omit.Val[int32] `db:"csv_file" ` + Deleted omitnull.Val[time.Time] `db:"deleted" ` + Geom omitnull.Val[string] `db:"geom" ` + H3cell omitnull.Val[string] `db:"h3cell" ` + ID omit.Val[int32] `db:"id,pk" ` + OrganizationID omit.Val[int32] `db:"organization_id" ` +} + +func (s FileuploadFlyoverAerialServiceSetter) SetColumns() []string { + vals := make([]string, 0, 10) + if s.Committed.IsValue() { + vals = append(vals, "committed") + } + if s.Condition.IsValue() { + vals = append(vals, "condition") + } + if s.Created.IsValue() { + vals = append(vals, "created") + } + if s.CreatorID.IsValue() { + vals = append(vals, "creator_id") + } + if s.CSVFile.IsValue() { + vals = append(vals, "csv_file") + } + if !s.Deleted.IsUnset() { + vals = append(vals, "deleted") + } + if !s.Geom.IsUnset() { + vals = append(vals, "geom") + } + if !s.H3cell.IsUnset() { + vals = append(vals, "h3cell") + } + if s.ID.IsValue() { + vals = append(vals, "id") + } + if s.OrganizationID.IsValue() { + vals = append(vals, "organization_id") + } + return vals +} + +func (s FileuploadFlyoverAerialServiceSetter) Overwrite(t *FileuploadFlyoverAerialService) { + if s.Committed.IsValue() { + t.Committed = s.Committed.MustGet() + } + if s.Condition.IsValue() { + t.Condition = s.Condition.MustGet() + } + if s.Created.IsValue() { + t.Created = s.Created.MustGet() + } + if s.CreatorID.IsValue() { + t.CreatorID = s.CreatorID.MustGet() + } + if s.CSVFile.IsValue() { + t.CSVFile = s.CSVFile.MustGet() + } + if !s.Deleted.IsUnset() { + t.Deleted = s.Deleted.MustGetNull() + } + if !s.Geom.IsUnset() { + t.Geom = s.Geom.MustGetNull() + } + if !s.H3cell.IsUnset() { + t.H3cell = s.H3cell.MustGetNull() + } + if s.ID.IsValue() { + t.ID = s.ID.MustGet() + } + if s.OrganizationID.IsValue() { + t.OrganizationID = s.OrganizationID.MustGet() + } +} + +func (s *FileuploadFlyoverAerialServiceSetter) Apply(q *dialect.InsertQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return FileuploadFlyoverAerialServices.BeforeInsertHooks.RunHooks(ctx, exec, s) + }) + + q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + vals := make([]bob.Expression, 10) + if s.Committed.IsValue() { + vals[0] = psql.Arg(s.Committed.MustGet()) + } else { + vals[0] = psql.Raw("DEFAULT") + } + + if s.Condition.IsValue() { + vals[1] = psql.Arg(s.Condition.MustGet()) + } else { + vals[1] = psql.Raw("DEFAULT") + } + + if s.Created.IsValue() { + vals[2] = psql.Arg(s.Created.MustGet()) + } else { + vals[2] = psql.Raw("DEFAULT") + } + + if s.CreatorID.IsValue() { + vals[3] = psql.Arg(s.CreatorID.MustGet()) + } else { + vals[3] = psql.Raw("DEFAULT") + } + + if s.CSVFile.IsValue() { + vals[4] = psql.Arg(s.CSVFile.MustGet()) + } else { + vals[4] = psql.Raw("DEFAULT") + } + + if !s.Deleted.IsUnset() { + vals[5] = psql.Arg(s.Deleted.MustGetNull()) + } else { + vals[5] = psql.Raw("DEFAULT") + } + + if !s.Geom.IsUnset() { + vals[6] = psql.Arg(s.Geom.MustGetNull()) + } else { + vals[6] = psql.Raw("DEFAULT") + } + + if !s.H3cell.IsUnset() { + vals[7] = psql.Arg(s.H3cell.MustGetNull()) + } else { + vals[7] = psql.Raw("DEFAULT") + } + + if s.ID.IsValue() { + vals[8] = psql.Arg(s.ID.MustGet()) + } else { + vals[8] = psql.Raw("DEFAULT") + } + + if s.OrganizationID.IsValue() { + vals[9] = psql.Arg(s.OrganizationID.MustGet()) + } else { + vals[9] = psql.Raw("DEFAULT") + } + + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") + })) +} + +func (s FileuploadFlyoverAerialServiceSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return um.Set(s.Expressions()...) +} + +func (s FileuploadFlyoverAerialServiceSetter) Expressions(prefix ...string) []bob.Expression { + exprs := make([]bob.Expression, 0, 10) + + if s.Committed.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "committed")...), + psql.Arg(s.Committed), + }}) + } + + if s.Condition.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "condition")...), + psql.Arg(s.Condition), + }}) + } + + if s.Created.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "created")...), + psql.Arg(s.Created), + }}) + } + + if s.CreatorID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "creator_id")...), + psql.Arg(s.CreatorID), + }}) + } + + if s.CSVFile.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "csv_file")...), + psql.Arg(s.CSVFile), + }}) + } + + if !s.Deleted.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "deleted")...), + psql.Arg(s.Deleted), + }}) + } + + if !s.Geom.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "geom")...), + psql.Arg(s.Geom), + }}) + } + + if !s.H3cell.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "h3cell")...), + psql.Arg(s.H3cell), + }}) + } + + if s.ID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "id")...), + psql.Arg(s.ID), + }}) + } + + if s.OrganizationID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "organization_id")...), + psql.Arg(s.OrganizationID), + }}) + } + + return exprs +} + +// FindFileuploadFlyoverAerialService retrieves a single record by primary key +// If cols is empty Find will return all columns. +func FindFileuploadFlyoverAerialService(ctx context.Context, exec bob.Executor, IDPK int32, cols ...string) (*FileuploadFlyoverAerialService, error) { + if len(cols) == 0 { + return FileuploadFlyoverAerialServices.Query( + sm.Where(FileuploadFlyoverAerialServices.Columns.ID.EQ(psql.Arg(IDPK))), + ).One(ctx, exec) + } + + return FileuploadFlyoverAerialServices.Query( + sm.Where(FileuploadFlyoverAerialServices.Columns.ID.EQ(psql.Arg(IDPK))), + sm.Columns(FileuploadFlyoverAerialServices.Columns.Only(cols...)), + ).One(ctx, exec) +} + +// FileuploadFlyoverAerialServiceExists checks the presence of a single record by primary key +func FileuploadFlyoverAerialServiceExists(ctx context.Context, exec bob.Executor, IDPK int32) (bool, error) { + return FileuploadFlyoverAerialServices.Query( + sm.Where(FileuploadFlyoverAerialServices.Columns.ID.EQ(psql.Arg(IDPK))), + ).Exists(ctx, exec) +} + +// AfterQueryHook is called after FileuploadFlyoverAerialService is retrieved from the database +func (o *FileuploadFlyoverAerialService) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = FileuploadFlyoverAerialServices.AfterSelectHooks.RunHooks(ctx, exec, FileuploadFlyoverAerialServiceSlice{o}) + case bob.QueryTypeInsert: + ctx, err = FileuploadFlyoverAerialServices.AfterInsertHooks.RunHooks(ctx, exec, FileuploadFlyoverAerialServiceSlice{o}) + case bob.QueryTypeUpdate: + ctx, err = FileuploadFlyoverAerialServices.AfterUpdateHooks.RunHooks(ctx, exec, FileuploadFlyoverAerialServiceSlice{o}) + case bob.QueryTypeDelete: + ctx, err = FileuploadFlyoverAerialServices.AfterDeleteHooks.RunHooks(ctx, exec, FileuploadFlyoverAerialServiceSlice{o}) + } + + return err +} + +// primaryKeyVals returns the primary key values of the FileuploadFlyoverAerialService +func (o *FileuploadFlyoverAerialService) primaryKeyVals() bob.Expression { + return psql.Arg(o.ID) +} + +func (o *FileuploadFlyoverAerialService) pkEQ() dialect.Expression { + return psql.Quote("fileupload.flyover_aerial_service", "id").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return o.primaryKeyVals().WriteSQL(ctx, w, d, start) + })) +} + +// Update uses an executor to update the FileuploadFlyoverAerialService +func (o *FileuploadFlyoverAerialService) Update(ctx context.Context, exec bob.Executor, s *FileuploadFlyoverAerialServiceSetter) error { + v, err := FileuploadFlyoverAerialServices.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) + if err != nil { + return err + } + + o.R = v.R + *o = *v + + return nil +} + +// Delete deletes a single FileuploadFlyoverAerialService record with an executor +func (o *FileuploadFlyoverAerialService) Delete(ctx context.Context, exec bob.Executor) error { + _, err := FileuploadFlyoverAerialServices.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) + return err +} + +// Reload refreshes the FileuploadFlyoverAerialService using the executor +func (o *FileuploadFlyoverAerialService) Reload(ctx context.Context, exec bob.Executor) error { + o2, err := FileuploadFlyoverAerialServices.Query( + sm.Where(FileuploadFlyoverAerialServices.Columns.ID.EQ(psql.Arg(o.ID))), + ).One(ctx, exec) + if err != nil { + return err + } + o2.R = o.R + *o = *o2 + + return nil +} + +// AfterQueryHook is called after FileuploadFlyoverAerialServiceSlice is retrieved from the database +func (o FileuploadFlyoverAerialServiceSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = FileuploadFlyoverAerialServices.AfterSelectHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeInsert: + ctx, err = FileuploadFlyoverAerialServices.AfterInsertHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeUpdate: + ctx, err = FileuploadFlyoverAerialServices.AfterUpdateHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeDelete: + ctx, err = FileuploadFlyoverAerialServices.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err +} + +func (o FileuploadFlyoverAerialServiceSlice) pkIN() dialect.Expression { + if len(o) == 0 { + return psql.Raw("NULL") + } + + return psql.Quote("fileupload.flyover_aerial_service", "id").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + pkPairs := make([]bob.Expression, len(o)) + for i, row := range o { + pkPairs[i] = row.primaryKeyVals() + } + return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") + })) +} + +// copyMatchingRows finds models in the given slice that have the same primary key +// then it first copies the existing relationships from the old model to the new model +// and then replaces the old model in the slice with the new model +func (o FileuploadFlyoverAerialServiceSlice) copyMatchingRows(from ...*FileuploadFlyoverAerialService) { + for i, old := range o { + for _, new := range from { + if new.ID != old.ID { + continue + } + new.R = old.R + o[i] = new + break + } + } +} + +// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" +func (o FileuploadFlyoverAerialServiceSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return FileuploadFlyoverAerialServices.BeforeUpdateHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *FileuploadFlyoverAerialService: + o.copyMatchingRows(retrieved) + case []*FileuploadFlyoverAerialService: + o.copyMatchingRows(retrieved...) + case FileuploadFlyoverAerialServiceSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a FileuploadFlyoverAerialService or a slice of FileuploadFlyoverAerialService + // then run the AfterUpdateHooks on the slice + _, err = FileuploadFlyoverAerialServices.AfterUpdateHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" +func (o FileuploadFlyoverAerialServiceSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { + return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return FileuploadFlyoverAerialServices.BeforeDeleteHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *FileuploadFlyoverAerialService: + o.copyMatchingRows(retrieved) + case []*FileuploadFlyoverAerialService: + o.copyMatchingRows(retrieved...) + case FileuploadFlyoverAerialServiceSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a FileuploadFlyoverAerialService or a slice of FileuploadFlyoverAerialService + // then run the AfterDeleteHooks on the slice + _, err = FileuploadFlyoverAerialServices.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +func (o FileuploadFlyoverAerialServiceSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals FileuploadFlyoverAerialServiceSetter) error { + if len(o) == 0 { + return nil + } + + _, err := FileuploadFlyoverAerialServices.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) + return err +} + +func (o FileuploadFlyoverAerialServiceSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + _, err := FileuploadFlyoverAerialServices.Delete(o.DeleteMod()).Exec(ctx, exec) + return err +} + +func (o FileuploadFlyoverAerialServiceSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + o2, err := FileuploadFlyoverAerialServices.Query(sm.Where(o.pkIN())).All(ctx, exec) + if err != nil { + return err + } + + o.copyMatchingRows(o2...) + + return nil +} + +// CreatorUser starts a query for related objects on user_ +func (o *FileuploadFlyoverAerialService) CreatorUser(mods ...bob.Mod[*dialect.SelectQuery]) UsersQuery { + return Users.Query(append(mods, + sm.Where(Users.Columns.ID.EQ(psql.Arg(o.CreatorID))), + )...) +} + +func (os FileuploadFlyoverAerialServiceSlice) CreatorUser(mods ...bob.Mod[*dialect.SelectQuery]) UsersQuery { + pkCreatorID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkCreatorID = append(pkCreatorID, o.CreatorID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkCreatorID), "integer[]")), + )) + + return Users.Query(append(mods, + sm.Where(psql.Group(Users.Columns.ID).OP("IN", PKArgExpr)), + )...) +} + +// CSVFileCSV starts a query for related objects on fileupload.csv +func (o *FileuploadFlyoverAerialService) CSVFileCSV(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadCSVSQuery { + return FileuploadCSVS.Query(append(mods, + sm.Where(FileuploadCSVS.Columns.FileID.EQ(psql.Arg(o.CSVFile))), + )...) +} + +func (os FileuploadFlyoverAerialServiceSlice) CSVFileCSV(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadCSVSQuery { + pkCSVFile := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkCSVFile = append(pkCSVFile, o.CSVFile) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkCSVFile), "integer[]")), + )) + + return FileuploadCSVS.Query(append(mods, + sm.Where(psql.Group(FileuploadCSVS.Columns.FileID).OP("IN", PKArgExpr)), + )...) +} + +// Organization starts a query for related objects on organization +func (o *FileuploadFlyoverAerialService) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery { + return Organizations.Query(append(mods, + sm.Where(Organizations.Columns.ID.EQ(psql.Arg(o.OrganizationID))), + )...) +} + +func (os FileuploadFlyoverAerialServiceSlice) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery { + pkOrganizationID := make(pgtypes.Array[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 attachFileuploadFlyoverAerialServiceCreatorUser0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService, user1 *User) (*FileuploadFlyoverAerialService, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + CreatorID: omit.From(user1.ID), + } + + err := fileuploadFlyoverAerialService0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachFileuploadFlyoverAerialServiceCreatorUser0: %w", err) + } + + return fileuploadFlyoverAerialService0, nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) InsertCreatorUser(ctx context.Context, exec bob.Executor, related *UserSetter) error { + var err error + + user1, err := Users.Insert(related).One(ctx, exec) + if err != nil { + return fmt.Errorf("inserting related objects: %w", err) + } + + _, err = attachFileuploadFlyoverAerialServiceCreatorUser0(ctx, exec, 1, fileuploadFlyoverAerialService0, user1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.CreatorUser = user1 + + user1.R.CreatorFlyoverAerialServices = append(user1.R.CreatorFlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) AttachCreatorUser(ctx context.Context, exec bob.Executor, user1 *User) error { + var err error + + _, err = attachFileuploadFlyoverAerialServiceCreatorUser0(ctx, exec, 1, fileuploadFlyoverAerialService0, user1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.CreatorUser = user1 + + user1.R.CreatorFlyoverAerialServices = append(user1.R.CreatorFlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +func attachFileuploadFlyoverAerialServiceCSVFileCSV0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService, fileuploadCSV1 *FileuploadCSV) (*FileuploadFlyoverAerialService, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + CSVFile: omit.From(fileuploadCSV1.FileID), + } + + err := fileuploadFlyoverAerialService0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachFileuploadFlyoverAerialServiceCSVFileCSV0: %w", err) + } + + return fileuploadFlyoverAerialService0, nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) InsertCSVFileCSV(ctx context.Context, exec bob.Executor, related *FileuploadCSVSetter) error { + var err error + + fileuploadCSV1, err := FileuploadCSVS.Insert(related).One(ctx, exec) + if err != nil { + return fmt.Errorf("inserting related objects: %w", err) + } + + _, err = attachFileuploadFlyoverAerialServiceCSVFileCSV0(ctx, exec, 1, fileuploadFlyoverAerialService0, fileuploadCSV1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.CSVFileCSV = fileuploadCSV1 + + fileuploadCSV1.R.CSVFileFlyoverAerialServices = append(fileuploadCSV1.R.CSVFileFlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) AttachCSVFileCSV(ctx context.Context, exec bob.Executor, fileuploadCSV1 *FileuploadCSV) error { + var err error + + _, err = attachFileuploadFlyoverAerialServiceCSVFileCSV0(ctx, exec, 1, fileuploadFlyoverAerialService0, fileuploadCSV1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.CSVFileCSV = fileuploadCSV1 + + fileuploadCSV1.R.CSVFileFlyoverAerialServices = append(fileuploadCSV1.R.CSVFileFlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +func attachFileuploadFlyoverAerialServiceOrganization0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService, organization1 *Organization) (*FileuploadFlyoverAerialService, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + OrganizationID: omit.From(organization1.ID), + } + + err := fileuploadFlyoverAerialService0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachFileuploadFlyoverAerialServiceOrganization0: %w", err) + } + + return fileuploadFlyoverAerialService0, nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) 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 = attachFileuploadFlyoverAerialServiceOrganization0(ctx, exec, 1, fileuploadFlyoverAerialService0, organization1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.Organization = organization1 + + organization1.R.FlyoverAerialServices = append(organization1.R.FlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +func (fileuploadFlyoverAerialService0 *FileuploadFlyoverAerialService) AttachOrganization(ctx context.Context, exec bob.Executor, organization1 *Organization) error { + var err error + + _, err = attachFileuploadFlyoverAerialServiceOrganization0(ctx, exec, 1, fileuploadFlyoverAerialService0, organization1) + if err != nil { + return err + } + + fileuploadFlyoverAerialService0.R.Organization = organization1 + + organization1.R.FlyoverAerialServices = append(organization1.R.FlyoverAerialServices, fileuploadFlyoverAerialService0) + + return nil +} + +type fileuploadFlyoverAerialServiceWhere[Q psql.Filterable] struct { + Committed psql.WhereMod[Q, bool] + Condition psql.WhereMod[Q, enums.FileuploadPoolconditiontype] + Created psql.WhereMod[Q, time.Time] + CreatorID psql.WhereMod[Q, int32] + CSVFile psql.WhereMod[Q, int32] + Deleted psql.WhereNullMod[Q, time.Time] + Geom psql.WhereNullMod[Q, string] + H3cell psql.WhereNullMod[Q, string] + ID psql.WhereMod[Q, int32] + OrganizationID psql.WhereMod[Q, int32] +} + +func (fileuploadFlyoverAerialServiceWhere[Q]) AliasedAs(alias string) fileuploadFlyoverAerialServiceWhere[Q] { + return buildFileuploadFlyoverAerialServiceWhere[Q](buildFileuploadFlyoverAerialServiceColumns(alias)) +} + +func buildFileuploadFlyoverAerialServiceWhere[Q psql.Filterable](cols fileuploadFlyoverAerialServiceColumns) fileuploadFlyoverAerialServiceWhere[Q] { + return fileuploadFlyoverAerialServiceWhere[Q]{ + Committed: psql.Where[Q, bool](cols.Committed), + Condition: psql.Where[Q, enums.FileuploadPoolconditiontype](cols.Condition), + Created: psql.Where[Q, time.Time](cols.Created), + CreatorID: psql.Where[Q, int32](cols.CreatorID), + CSVFile: psql.Where[Q, int32](cols.CSVFile), + Deleted: psql.WhereNull[Q, time.Time](cols.Deleted), + Geom: psql.WhereNull[Q, string](cols.Geom), + H3cell: psql.WhereNull[Q, string](cols.H3cell), + ID: psql.Where[Q, int32](cols.ID), + OrganizationID: psql.Where[Q, int32](cols.OrganizationID), + } +} + +func (o *FileuploadFlyoverAerialService) Preload(name string, retrieved any) error { + if o == nil { + return nil + } + + switch name { + case "CreatorUser": + rel, ok := retrieved.(*User) + if !ok { + return fmt.Errorf("fileuploadFlyoverAerialService cannot load %T as %q", retrieved, name) + } + + o.R.CreatorUser = rel + + if rel != nil { + rel.R.CreatorFlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + } + return nil + case "CSVFileCSV": + rel, ok := retrieved.(*FileuploadCSV) + if !ok { + return fmt.Errorf("fileuploadFlyoverAerialService cannot load %T as %q", retrieved, name) + } + + o.R.CSVFileCSV = rel + + if rel != nil { + rel.R.CSVFileFlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + } + return nil + case "Organization": + rel, ok := retrieved.(*Organization) + if !ok { + return fmt.Errorf("fileuploadFlyoverAerialService cannot load %T as %q", retrieved, name) + } + + o.R.Organization = rel + + if rel != nil { + rel.R.FlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + } + return nil + default: + return fmt.Errorf("fileuploadFlyoverAerialService has no relationship %q", name) + } +} + +type fileuploadFlyoverAerialServicePreloader struct { + CreatorUser func(...psql.PreloadOption) psql.Preloader + CSVFileCSV func(...psql.PreloadOption) psql.Preloader + Organization func(...psql.PreloadOption) psql.Preloader +} + +func buildFileuploadFlyoverAerialServicePreloader() fileuploadFlyoverAerialServicePreloader { + return fileuploadFlyoverAerialServicePreloader{ + CreatorUser: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*User, UserSlice](psql.PreloadRel{ + Name: "CreatorUser", + Sides: []psql.PreloadSide{ + { + From: FileuploadFlyoverAerialServices, + To: Users, + FromColumns: []string{"creator_id"}, + ToColumns: []string{"id"}, + }, + }, + }, Users.Columns.Names(), opts...) + }, + CSVFileCSV: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*FileuploadCSV, FileuploadCSVSlice](psql.PreloadRel{ + Name: "CSVFileCSV", + Sides: []psql.PreloadSide{ + { + From: FileuploadFlyoverAerialServices, + To: FileuploadCSVS, + FromColumns: []string{"csv_file"}, + ToColumns: []string{"file_id"}, + }, + }, + }, FileuploadCSVS.Columns.Names(), opts...) + }, + Organization: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*Organization, OrganizationSlice](psql.PreloadRel{ + Name: "Organization", + Sides: []psql.PreloadSide{ + { + From: FileuploadFlyoverAerialServices, + To: Organizations, + FromColumns: []string{"organization_id"}, + ToColumns: []string{"id"}, + }, + }, + }, Organizations.Columns.Names(), opts...) + }, + } +} + +type fileuploadFlyoverAerialServiceThenLoader[Q orm.Loadable] struct { + CreatorUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CSVFileCSV func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildFileuploadFlyoverAerialServiceThenLoader[Q orm.Loadable]() fileuploadFlyoverAerialServiceThenLoader[Q] { + type CreatorUserLoadInterface interface { + LoadCreatorUser(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + type CSVFileCSVLoadInterface interface { + LoadCSVFileCSV(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + type OrganizationLoadInterface interface { + LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return fileuploadFlyoverAerialServiceThenLoader[Q]{ + CreatorUser: thenLoadBuilder[Q]( + "CreatorUser", + func(ctx context.Context, exec bob.Executor, retrieved CreatorUserLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCreatorUser(ctx, exec, mods...) + }, + ), + CSVFileCSV: thenLoadBuilder[Q]( + "CSVFileCSV", + func(ctx context.Context, exec bob.Executor, retrieved CSVFileCSVLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCSVFileCSV(ctx, exec, mods...) + }, + ), + 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...) + }, + ), + } +} + +// LoadCreatorUser loads the fileuploadFlyoverAerialService's CreatorUser into the .R struct +func (o *FileuploadFlyoverAerialService) LoadCreatorUser(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.CreatorUser = nil + + related, err := o.CreatorUser(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.CreatorFlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + + o.R.CreatorUser = related + return nil +} + +// LoadCreatorUser loads the fileuploadFlyoverAerialService's CreatorUser into the .R struct +func (os FileuploadFlyoverAerialServiceSlice) LoadCreatorUser(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + users, err := os.CreatorUser(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range users { + + if !(o.CreatorID == rel.ID) { + continue + } + + rel.R.CreatorFlyoverAerialServices = append(rel.R.CreatorFlyoverAerialServices, o) + + o.R.CreatorUser = rel + break + } + } + + return nil +} + +// LoadCSVFileCSV loads the fileuploadFlyoverAerialService's CSVFileCSV into the .R struct +func (o *FileuploadFlyoverAerialService) LoadCSVFileCSV(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.CSVFileCSV = nil + + related, err := o.CSVFileCSV(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.CSVFileFlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + + o.R.CSVFileCSV = related + return nil +} + +// LoadCSVFileCSV loads the fileuploadFlyoverAerialService's CSVFileCSV into the .R struct +func (os FileuploadFlyoverAerialServiceSlice) LoadCSVFileCSV(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + fileuploadCSVS, err := os.CSVFileCSV(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range fileuploadCSVS { + + if !(o.CSVFile == rel.FileID) { + continue + } + + rel.R.CSVFileFlyoverAerialServices = append(rel.R.CSVFileFlyoverAerialServices, o) + + o.R.CSVFileCSV = rel + break + } + } + + return nil +} + +// LoadOrganization loads the fileuploadFlyoverAerialService's Organization into the .R struct +func (o *FileuploadFlyoverAerialService) 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.FlyoverAerialServices = FileuploadFlyoverAerialServiceSlice{o} + + o.R.Organization = related + return nil +} + +// LoadOrganization loads the fileuploadFlyoverAerialService's Organization into the .R struct +func (os FileuploadFlyoverAerialServiceSlice) 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 == rel.ID) { + continue + } + + rel.R.FlyoverAerialServices = append(rel.R.FlyoverAerialServices, o) + + o.R.Organization = rel + break + } + } + + return nil +} + +type fileuploadFlyoverAerialServiceJoins[Q dialect.Joinable] struct { + typ string + CreatorUser modAs[Q, userColumns] + CSVFileCSV modAs[Q, fileuploadCSVColumns] + Organization modAs[Q, organizationColumns] +} + +func (j fileuploadFlyoverAerialServiceJoins[Q]) aliasedAs(alias string) fileuploadFlyoverAerialServiceJoins[Q] { + return buildFileuploadFlyoverAerialServiceJoins[Q](buildFileuploadFlyoverAerialServiceColumns(alias), j.typ) +} + +func buildFileuploadFlyoverAerialServiceJoins[Q dialect.Joinable](cols fileuploadFlyoverAerialServiceColumns, typ string) fileuploadFlyoverAerialServiceJoins[Q] { + return fileuploadFlyoverAerialServiceJoins[Q]{ + typ: typ, + CreatorUser: modAs[Q, userColumns]{ + c: Users.Columns, + f: func(to userColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, Users.Name().As(to.Alias())).On( + to.ID.EQ(cols.CreatorID), + )) + } + + return mods + }, + }, + CSVFileCSV: modAs[Q, fileuploadCSVColumns]{ + c: FileuploadCSVS.Columns, + f: func(to fileuploadCSVColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, FileuploadCSVS.Name().As(to.Alias())).On( + to.FileID.EQ(cols.CSVFile), + )) + } + + return mods + }, + }, + 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 + }, + }, + } +} diff --git a/db/models/organization.bob.go b/db/models/organization.bob.go index 2e8d436b..e9810737 100644 --- a/db/models/organization.bob.go +++ b/db/models/organization.bob.go @@ -113,6 +113,7 @@ type organizationR struct { Zones2s FieldseekerZones2Slice // fieldseeker.zones2.zones2_organization_id_fkey FieldseekerSyncs FieldseekerSyncSlice // fieldseeker_sync.fieldseeker_sync_organization_id_fkey Files FileuploadFileSlice // fileupload.file.file_organization_id_fkey + FlyoverAerialServices FileuploadFlyoverAerialServiceSlice // fileupload.flyover_aerial_service.flyover_aerial_service_organization_id_fkey Pools FileuploadPoolSlice // fileupload.pool.pool_organization_id_fkey H3Aggregations H3AggregationSlice // h3_aggregation.h3_aggregation_organization_id_fkey NoteAudios NoteAudioSlice // note_audio.note_audio_organization_id_fkey @@ -1735,6 +1736,30 @@ func (os OrganizationSlice) Files(mods ...bob.Mod[*dialect.SelectQuery]) Fileupl )...) } +// FlyoverAerialServices starts a query for related objects on fileupload.flyover_aerial_service +func (o *Organization) FlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(FileuploadFlyoverAerialServices.Columns.OrganizationID.EQ(psql.Arg(o.ID))), + )...) +} + +func (os OrganizationSlice) FlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + pkID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkID = append(pkID, o.ID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkID), "integer[]")), + )) + + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(psql.Group(FileuploadFlyoverAerialServices.Columns.OrganizationID).OP("IN", PKArgExpr)), + )...) +} + // Pools starts a query for related objects on fileupload.pool func (o *Organization) Pools(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadPoolsQuery { return FileuploadPools.Query(append(mods, @@ -4281,6 +4306,74 @@ func (organization0 *Organization) AttachFiles(ctx context.Context, exec bob.Exe return nil } +func insertOrganizationFlyoverAerialServices0(ctx context.Context, exec bob.Executor, fileuploadFlyoverAerialServices1 []*FileuploadFlyoverAerialServiceSetter, organization0 *Organization) (FileuploadFlyoverAerialServiceSlice, error) { + for i := range fileuploadFlyoverAerialServices1 { + fileuploadFlyoverAerialServices1[i].OrganizationID = omit.From(organization0.ID) + } + + ret, err := FileuploadFlyoverAerialServices.Insert(bob.ToMods(fileuploadFlyoverAerialServices1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertOrganizationFlyoverAerialServices0: %w", err) + } + + return ret, nil +} + +func attachOrganizationFlyoverAerialServices0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialServices1 FileuploadFlyoverAerialServiceSlice, organization0 *Organization) (FileuploadFlyoverAerialServiceSlice, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + OrganizationID: omit.From(organization0.ID), + } + + err := fileuploadFlyoverAerialServices1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachOrganizationFlyoverAerialServices0: %w", err) + } + + return fileuploadFlyoverAerialServices1, nil +} + +func (organization0 *Organization) InsertFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialServiceSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + fileuploadFlyoverAerialServices1, err := insertOrganizationFlyoverAerialServices0(ctx, exec, related, organization0) + if err != nil { + return err + } + + organization0.R.FlyoverAerialServices = append(organization0.R.FlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range fileuploadFlyoverAerialServices1 { + rel.R.Organization = organization0 + } + return nil +} + +func (organization0 *Organization) AttachFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialService) error { + if len(related) == 0 { + return nil + } + + var err error + fileuploadFlyoverAerialServices1 := FileuploadFlyoverAerialServiceSlice(related) + + _, err = attachOrganizationFlyoverAerialServices0(ctx, exec, len(related), fileuploadFlyoverAerialServices1, organization0) + if err != nil { + return err + } + + organization0.R.FlyoverAerialServices = append(organization0.R.FlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range related { + rel.R.Organization = organization0 + } + + return nil +} + func insertOrganizationPools0(ctx context.Context, exec bob.Executor, fileuploadPools1 []*FileuploadPoolSetter, organization0 *Organization) (FileuploadPoolSlice, error) { for i := range fileuploadPools1 { fileuploadPools1[i].OrganizationID = omit.From(organization0.ID) @@ -5473,6 +5566,20 @@ func (o *Organization) Preload(name string, retrieved any) error { o.R.Files = rels + for _, rel := range rels { + if rel != nil { + rel.R.Organization = o + } + } + return nil + case "FlyoverAerialServices": + rels, ok := retrieved.(FileuploadFlyoverAerialServiceSlice) + if !ok { + return fmt.Errorf("organization cannot load %T as %q", retrieved, name) + } + + o.R.FlyoverAerialServices = rels + for _, rel := range rels { if rel != nil { rel.R.Organization = o @@ -5691,6 +5798,7 @@ type organizationThenLoader[Q orm.Loadable] struct { Zones2s func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] FieldseekerSyncs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Files func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + FlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Pools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] H3Aggregations func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] NoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -5806,6 +5914,9 @@ func buildOrganizationThenLoader[Q orm.Loadable]() organizationThenLoader[Q] { type FilesLoadInterface interface { LoadFiles(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type FlyoverAerialServicesLoadInterface interface { + LoadFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type PoolsLoadInterface interface { LoadPools(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -6042,6 +6153,12 @@ func buildOrganizationThenLoader[Q orm.Loadable]() organizationThenLoader[Q] { return retrieved.LoadFiles(ctx, exec, mods...) }, ), + FlyoverAerialServices: thenLoadBuilder[Q]( + "FlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved FlyoverAerialServicesLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadFlyoverAerialServices(ctx, exec, mods...) + }, + ), Pools: thenLoadBuilder[Q]( "Pools", func(ctx context.Context, exec bob.Executor, retrieved PoolsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -8219,6 +8336,67 @@ func (os OrganizationSlice) LoadFiles(ctx context.Context, exec bob.Executor, mo return nil } +// LoadFlyoverAerialServices loads the organization's FlyoverAerialServices into the .R struct +func (o *Organization) LoadFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.FlyoverAerialServices = nil + + related, err := o.FlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.Organization = o + } + + o.R.FlyoverAerialServices = related + return nil +} + +// LoadFlyoverAerialServices loads the organization's FlyoverAerialServices into the .R struct +func (os OrganizationSlice) LoadFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + fileuploadFlyoverAerialServices, err := os.FlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.FlyoverAerialServices = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range fileuploadFlyoverAerialServices { + + if !(o.ID == rel.OrganizationID) { + continue + } + + rel.R.Organization = o + + o.R.FlyoverAerialServices = append(o.R.FlyoverAerialServices, rel) + } + } + + return nil +} + // LoadPools loads the organization's Pools into the .R struct func (o *Organization) LoadPools(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -8862,6 +9040,7 @@ type organizationC struct { Zones2s *int64 FieldseekerSyncs *int64 Files *int64 + FlyoverAerialServices *int64 Pools *int64 H3Aggregations *int64 NoteAudios *int64 @@ -8947,6 +9126,8 @@ func (o *Organization) PreloadCount(name string, count int64) error { o.C.FieldseekerSyncs = &count case "Files": o.C.Files = &count + case "FlyoverAerialServices": + o.C.FlyoverAerialServices = &count case "Pools": o.C.Pools = &count case "H3Aggregations": @@ -9002,6 +9183,7 @@ type organizationCountPreloader struct { Zones2s func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader FieldseekerSyncs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader Files func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader + FlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader Pools func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader H3Aggregations func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader NoteAudios func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader @@ -9598,6 +9780,23 @@ func buildOrganizationCountPreloader() organizationCountPreloader { return psql.Group(psql.Select(subqueryMods...).Expression) }) }, + FlyoverAerialServices: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { + return countPreloader[*Organization]("FlyoverAerialServices", func(parent string) bob.Expression { + // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) + if parent == "" { + parent = Organizations.Alias() + } + + subqueryMods := []bob.Mod[*dialect.SelectQuery]{ + sm.Columns(psql.Raw("count(*)")), + + sm.From(FileuploadFlyoverAerialServices.Name()), + sm.Where(psql.Quote(FileuploadFlyoverAerialServices.Alias(), "organization_id").EQ(psql.Quote(parent, "id"))), + } + subqueryMods = append(subqueryMods, mods...) + return psql.Group(psql.Select(subqueryMods...).Expression) + }) + }, Pools: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { return countPreloader[*Organization]("Pools", func(parent string) bob.Expression { // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) @@ -9772,6 +9971,7 @@ type organizationCountThenLoader[Q orm.Loadable] struct { Zones2s func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] FieldseekerSyncs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Files func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + FlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Pools func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] H3Aggregations func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] NoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -9885,6 +10085,9 @@ func buildOrganizationCountThenLoader[Q orm.Loadable]() organizationCountThenLoa type FilesCountInterface interface { LoadCountFiles(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type FlyoverAerialServicesCountInterface interface { + LoadCountFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type PoolsCountInterface interface { LoadCountPools(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -10115,6 +10318,12 @@ func buildOrganizationCountThenLoader[Q orm.Loadable]() organizationCountThenLoa return retrieved.LoadCountFiles(ctx, exec, mods...) }, ), + FlyoverAerialServices: countThenLoadBuilder[Q]( + "FlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved FlyoverAerialServicesCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCountFlyoverAerialServices(ctx, exec, mods...) + }, + ), Pools: countThenLoadBuilder[Q]( "Pools", func(ctx context.Context, exec bob.Executor, retrieved PoolsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -11186,6 +11395,36 @@ func (os OrganizationSlice) LoadCountFiles(ctx context.Context, exec bob.Executo return nil } +// LoadCountFlyoverAerialServices loads the count of FlyoverAerialServices into the C struct +func (o *Organization) LoadCountFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + count, err := o.FlyoverAerialServices(mods...).Count(ctx, exec) + if err != nil { + return err + } + + o.C.FlyoverAerialServices = &count + return nil +} + +// LoadCountFlyoverAerialServices loads the count of FlyoverAerialServices for a slice +func (os OrganizationSlice) LoadCountFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + for _, o := range os { + if err := o.LoadCountFlyoverAerialServices(ctx, exec, mods...); err != nil { + return err + } + } + + return nil +} + // LoadCountPools loads the count of Pools into the C struct func (o *Organization) LoadCountPools(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -11462,6 +11701,7 @@ type organizationJoins[Q dialect.Joinable] struct { Zones2s modAs[Q, fieldseekerZones2Columns] FieldseekerSyncs modAs[Q, fieldseekerSyncColumns] Files modAs[Q, fileuploadFileColumns] + FlyoverAerialServices modAs[Q, fileuploadFlyoverAerialServiceColumns] Pools modAs[Q, fileuploadPoolColumns] H3Aggregations modAs[Q, h3AggregationColumns] NoteAudios modAs[Q, noteAudioColumns] @@ -11973,6 +12213,20 @@ func buildOrganizationJoins[Q dialect.Joinable](cols organizationColumns, typ st return mods }, }, + FlyoverAerialServices: modAs[Q, fileuploadFlyoverAerialServiceColumns]{ + c: FileuploadFlyoverAerialServices.Columns, + f: func(to fileuploadFlyoverAerialServiceColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, FileuploadFlyoverAerialServices.Name().As(to.Alias())).On( + to.OrganizationID.EQ(cols.ID), + )) + } + + return mods + }, + }, Pools: modAs[Q, fileuploadPoolColumns]{ c: FileuploadPools.Columns, f: func(to fileuploadPoolColumns) bob.Mod[Q] { diff --git a/db/models/user_.bob.go b/db/models/user_.bob.go index bc742c07..15692e9d 100644 --- a/db/models/user_.bob.go +++ b/db/models/user_.bob.go @@ -58,20 +58,21 @@ type UsersQuery = *psql.ViewQuery[*User, UserSlice] // userR is where relationships are stored. type userR struct { - UserOauthTokens ArcgisOauthTokenSlice // arcgis.oauth_token.oauth_token_user_id_fkey - PublicUserUser ArcgisUserSlice // arcgis.user_.user__public_user_id_fkey - CreatorComplianceReportRequests ComplianceReportRequestSlice // compliance_report_request.compliance_report_request_creator_fkey - CreatorFiles FileuploadFileSlice // fileupload.file.file_creator_id_fkey - FileuploadPool FileuploadPoolSlice // fileupload.pool.pool_creator_id_fkey - CreatorNoteAudios NoteAudioSlice // note_audio.note_audio_creator_id_fkey - DeletorNoteAudios NoteAudioSlice // note_audio.note_audio_deletor_id_fkey - CreatorNoteImages NoteImageSlice // note_image.note_image_creator_id_fkey - DeletorNoteImages NoteImageSlice // note_image.note_image_deletor_id_fkey - UserNotifications NotificationSlice // notification.notification_user_id_fkey - CreatorPools PoolSlice // pool.pool_creator_id_fkey - CreatorResidents ResidentSlice // resident.resident_creator_fkey - CreatorSites SiteSlice // site.site_creator_id_fkey - Organization *Organization // user_.user__organization_id_fkey + UserOauthTokens ArcgisOauthTokenSlice // arcgis.oauth_token.oauth_token_user_id_fkey + PublicUserUser ArcgisUserSlice // arcgis.user_.user__public_user_id_fkey + CreatorComplianceReportRequests ComplianceReportRequestSlice // compliance_report_request.compliance_report_request_creator_fkey + CreatorFiles FileuploadFileSlice // fileupload.file.file_creator_id_fkey + CreatorFlyoverAerialServices FileuploadFlyoverAerialServiceSlice // fileupload.flyover_aerial_service.flyover_aerial_service_creator_id_fkey + FileuploadPool FileuploadPoolSlice // fileupload.pool.pool_creator_id_fkey + CreatorNoteAudios NoteAudioSlice // note_audio.note_audio_creator_id_fkey + DeletorNoteAudios NoteAudioSlice // note_audio.note_audio_deletor_id_fkey + CreatorNoteImages NoteImageSlice // note_image.note_image_creator_id_fkey + DeletorNoteImages NoteImageSlice // note_image.note_image_deletor_id_fkey + UserNotifications NotificationSlice // notification.notification_user_id_fkey + CreatorPools PoolSlice // pool.pool_creator_id_fkey + CreatorResidents ResidentSlice // resident.resident_creator_fkey + CreatorSites SiteSlice // site.site_creator_id_fkey + Organization *Organization // user_.user__organization_id_fkey } func buildUserColumns(alias string) userColumns { @@ -736,6 +737,30 @@ func (os UserSlice) CreatorFiles(mods ...bob.Mod[*dialect.SelectQuery]) Fileuplo )...) } +// CreatorFlyoverAerialServices starts a query for related objects on fileupload.flyover_aerial_service +func (o *User) CreatorFlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(FileuploadFlyoverAerialServices.Columns.CreatorID.EQ(psql.Arg(o.ID))), + )...) +} + +func (os UserSlice) CreatorFlyoverAerialServices(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadFlyoverAerialServicesQuery { + pkID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkID = append(pkID, o.ID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkID), "integer[]")), + )) + + return FileuploadFlyoverAerialServices.Query(append(mods, + sm.Where(psql.Group(FileuploadFlyoverAerialServices.Columns.CreatorID).OP("IN", PKArgExpr)), + )...) +} + // FileuploadPool starts a query for related objects on fileupload.pool func (o *User) FileuploadPool(mods ...bob.Mod[*dialect.SelectQuery]) FileuploadPoolsQuery { return FileuploadPools.Query(append(mods, @@ -1248,6 +1273,74 @@ func (user0 *User) AttachCreatorFiles(ctx context.Context, exec bob.Executor, re return nil } +func insertUserCreatorFlyoverAerialServices0(ctx context.Context, exec bob.Executor, fileuploadFlyoverAerialServices1 []*FileuploadFlyoverAerialServiceSetter, user0 *User) (FileuploadFlyoverAerialServiceSlice, error) { + for i := range fileuploadFlyoverAerialServices1 { + fileuploadFlyoverAerialServices1[i].CreatorID = omit.From(user0.ID) + } + + ret, err := FileuploadFlyoverAerialServices.Insert(bob.ToMods(fileuploadFlyoverAerialServices1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertUserCreatorFlyoverAerialServices0: %w", err) + } + + return ret, nil +} + +func attachUserCreatorFlyoverAerialServices0(ctx context.Context, exec bob.Executor, count int, fileuploadFlyoverAerialServices1 FileuploadFlyoverAerialServiceSlice, user0 *User) (FileuploadFlyoverAerialServiceSlice, error) { + setter := &FileuploadFlyoverAerialServiceSetter{ + CreatorID: omit.From(user0.ID), + } + + err := fileuploadFlyoverAerialServices1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachUserCreatorFlyoverAerialServices0: %w", err) + } + + return fileuploadFlyoverAerialServices1, nil +} + +func (user0 *User) InsertCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialServiceSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + fileuploadFlyoverAerialServices1, err := insertUserCreatorFlyoverAerialServices0(ctx, exec, related, user0) + if err != nil { + return err + } + + user0.R.CreatorFlyoverAerialServices = append(user0.R.CreatorFlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range fileuploadFlyoverAerialServices1 { + rel.R.CreatorUser = user0 + } + return nil +} + +func (user0 *User) AttachCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, related ...*FileuploadFlyoverAerialService) error { + if len(related) == 0 { + return nil + } + + var err error + fileuploadFlyoverAerialServices1 := FileuploadFlyoverAerialServiceSlice(related) + + _, err = attachUserCreatorFlyoverAerialServices0(ctx, exec, len(related), fileuploadFlyoverAerialServices1, user0) + if err != nil { + return err + } + + user0.R.CreatorFlyoverAerialServices = append(user0.R.CreatorFlyoverAerialServices, fileuploadFlyoverAerialServices1...) + + for _, rel := range related { + rel.R.CreatorUser = user0 + } + + return nil +} + func insertUserFileuploadPool0(ctx context.Context, exec bob.Executor, fileuploadPools1 []*FileuploadPoolSetter, user0 *User) (FileuploadPoolSlice, error) { for i := range fileuploadPools1 { fileuploadPools1[i].CreatorID = omit.From(user0.ID) @@ -2002,6 +2095,20 @@ func (o *User) Preload(name string, retrieved any) error { o.R.CreatorFiles = rels + for _, rel := range rels { + if rel != nil { + rel.R.CreatorUser = o + } + } + return nil + case "CreatorFlyoverAerialServices": + rels, ok := retrieved.(FileuploadFlyoverAerialServiceSlice) + if !ok { + return fmt.Errorf("user cannot load %T as %q", retrieved, name) + } + + o.R.CreatorFlyoverAerialServices = rels + for _, rel := range rels { if rel != nil { rel.R.CreatorUser = o @@ -2178,6 +2285,7 @@ type userThenLoader[Q orm.Loadable] struct { PublicUserUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorComplianceReportRequests func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorFiles func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CreatorFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] FileuploadPool func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] DeletorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -2203,6 +2311,9 @@ func buildUserThenLoader[Q orm.Loadable]() userThenLoader[Q] { type CreatorFilesLoadInterface interface { LoadCreatorFiles(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type CreatorFlyoverAerialServicesLoadInterface interface { + LoadCreatorFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type FileuploadPoolLoadInterface interface { LoadFileuploadPool(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -2259,6 +2370,12 @@ func buildUserThenLoader[Q orm.Loadable]() userThenLoader[Q] { return retrieved.LoadCreatorFiles(ctx, exec, mods...) }, ), + CreatorFlyoverAerialServices: thenLoadBuilder[Q]( + "CreatorFlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved CreatorFlyoverAerialServicesLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCreatorFlyoverAerialServices(ctx, exec, mods...) + }, + ), FileuploadPool: thenLoadBuilder[Q]( "FileuploadPool", func(ctx context.Context, exec bob.Executor, retrieved FileuploadPoolLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -2566,6 +2683,67 @@ func (os UserSlice) LoadCreatorFiles(ctx context.Context, exec bob.Executor, mod return nil } +// LoadCreatorFlyoverAerialServices loads the user's CreatorFlyoverAerialServices into the .R struct +func (o *User) LoadCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.CreatorFlyoverAerialServices = nil + + related, err := o.CreatorFlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.CreatorUser = o + } + + o.R.CreatorFlyoverAerialServices = related + return nil +} + +// LoadCreatorFlyoverAerialServices loads the user's CreatorFlyoverAerialServices into the .R struct +func (os UserSlice) LoadCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + fileuploadFlyoverAerialServices, err := os.CreatorFlyoverAerialServices(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.CreatorFlyoverAerialServices = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range fileuploadFlyoverAerialServices { + + if !(o.ID == rel.CreatorID) { + continue + } + + rel.R.CreatorUser = o + + o.R.CreatorFlyoverAerialServices = append(o.R.CreatorFlyoverAerialServices, rel) + } + } + + return nil +} + // LoadFileuploadPool loads the user's FileuploadPool into the .R struct func (o *User) LoadFileuploadPool(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -3179,6 +3357,7 @@ type userC struct { PublicUserUser *int64 CreatorComplianceReportRequests *int64 CreatorFiles *int64 + CreatorFlyoverAerialServices *int64 FileuploadPool *int64 CreatorNoteAudios *int64 DeletorNoteAudios *int64 @@ -3205,6 +3384,8 @@ func (o *User) PreloadCount(name string, count int64) error { o.C.CreatorComplianceReportRequests = &count case "CreatorFiles": o.C.CreatorFiles = &count + case "CreatorFlyoverAerialServices": + o.C.CreatorFlyoverAerialServices = &count case "FileuploadPool": o.C.FileuploadPool = &count case "CreatorNoteAudios": @@ -3232,6 +3413,7 @@ type userCountPreloader struct { PublicUserUser func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader CreatorComplianceReportRequests func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader CreatorFiles func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader + CreatorFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader FileuploadPool func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader CreatorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader DeletorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader @@ -3313,6 +3495,23 @@ func buildUserCountPreloader() userCountPreloader { return psql.Group(psql.Select(subqueryMods...).Expression) }) }, + CreatorFlyoverAerialServices: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { + return countPreloader[*User]("CreatorFlyoverAerialServices", func(parent string) bob.Expression { + // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) + if parent == "" { + parent = Users.Alias() + } + + subqueryMods := []bob.Mod[*dialect.SelectQuery]{ + sm.Columns(psql.Raw("count(*)")), + + sm.From(FileuploadFlyoverAerialServices.Name()), + sm.Where(psql.Quote(FileuploadFlyoverAerialServices.Alias(), "creator_id").EQ(psql.Quote(parent, "id"))), + } + subqueryMods = append(subqueryMods, mods...) + return psql.Group(psql.Select(subqueryMods...).Expression) + }) + }, FileuploadPool: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { return countPreloader[*User]("FileuploadPool", func(parent string) bob.Expression { // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) @@ -3474,6 +3673,7 @@ type userCountThenLoader[Q orm.Loadable] struct { PublicUserUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorComplianceReportRequests func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorFiles func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + CreatorFlyoverAerialServices func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] FileuploadPool func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] CreatorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] DeletorNoteAudios func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -3498,6 +3698,9 @@ func buildUserCountThenLoader[Q orm.Loadable]() userCountThenLoader[Q] { type CreatorFilesCountInterface interface { LoadCountCreatorFiles(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type CreatorFlyoverAerialServicesCountInterface interface { + LoadCountCreatorFlyoverAerialServices(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type FileuploadPoolCountInterface interface { LoadCountFileuploadPool(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -3551,6 +3754,12 @@ func buildUserCountThenLoader[Q orm.Loadable]() userCountThenLoader[Q] { return retrieved.LoadCountCreatorFiles(ctx, exec, mods...) }, ), + CreatorFlyoverAerialServices: countThenLoadBuilder[Q]( + "CreatorFlyoverAerialServices", + func(ctx context.Context, exec bob.Executor, retrieved CreatorFlyoverAerialServicesCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCountCreatorFlyoverAerialServices(ctx, exec, mods...) + }, + ), FileuploadPool: countThenLoadBuilder[Q]( "FileuploadPool", func(ctx context.Context, exec bob.Executor, retrieved FileuploadPoolCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -3728,6 +3937,36 @@ func (os UserSlice) LoadCountCreatorFiles(ctx context.Context, exec bob.Executor return nil } +// LoadCountCreatorFlyoverAerialServices loads the count of CreatorFlyoverAerialServices into the C struct +func (o *User) LoadCountCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + count, err := o.CreatorFlyoverAerialServices(mods...).Count(ctx, exec) + if err != nil { + return err + } + + o.C.CreatorFlyoverAerialServices = &count + return nil +} + +// LoadCountCreatorFlyoverAerialServices loads the count of CreatorFlyoverAerialServices for a slice +func (os UserSlice) LoadCountCreatorFlyoverAerialServices(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + for _, o := range os { + if err := o.LoadCountCreatorFlyoverAerialServices(ctx, exec, mods...); err != nil { + return err + } + } + + return nil +} + // LoadCountFileuploadPool loads the count of FileuploadPool into the C struct func (o *User) LoadCountFileuploadPool(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -4004,6 +4243,7 @@ type userJoins[Q dialect.Joinable] struct { PublicUserUser modAs[Q, arcgisuserColumns] CreatorComplianceReportRequests modAs[Q, complianceReportRequestColumns] CreatorFiles modAs[Q, fileuploadFileColumns] + CreatorFlyoverAerialServices modAs[Q, fileuploadFlyoverAerialServiceColumns] FileuploadPool modAs[Q, fileuploadPoolColumns] CreatorNoteAudios modAs[Q, noteAudioColumns] DeletorNoteAudios modAs[Q, noteAudioColumns] @@ -4079,6 +4319,20 @@ func buildUserJoins[Q dialect.Joinable](cols userColumns, typ string) userJoins[ return mods }, }, + CreatorFlyoverAerialServices: modAs[Q, fileuploadFlyoverAerialServiceColumns]{ + c: FileuploadFlyoverAerialServices.Columns, + f: func(to fileuploadFlyoverAerialServiceColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, FileuploadFlyoverAerialServices.Name().As(to.Alias())).On( + to.CreatorID.EQ(cols.ID), + )) + } + + return mods + }, + }, FileuploadPool: modAs[Q, fileuploadPoolColumns]{ c: FileuploadPools.Columns, f: func(to fileuploadPoolColumns) bob.Mod[Q] { diff --git a/html/func.go b/html/func.go index d21c96fb..fa20d290 100644 --- a/html/func.go +++ b/html/func.go @@ -79,6 +79,8 @@ func displayUploadType(s string) string { switch s { case "PoolList": return "Green Pool List" + case "Flyover": + return "Flyover" default: return "Unknown upload type" } diff --git a/html/template/sync/upload-by-id.html b/html/template/sync/upload-by-id.html index 6598b1a5..233d5de7 100644 --- a/html/template/sync/upload-by-id.html +++ b/html/template/sync/upload-by-id.html @@ -204,12 +204,14 @@ document.addEventListener('DOMContentLoaded', onLoad);
-
+
- +
+ +
{{ end }} diff --git a/html/template/sync/upload-csv-pool-bob.html b/html/template/sync/upload-csv-pool-flyover.html similarity index 98% rename from html/template/sync/upload-csv-pool-bob.html rename to html/template/sync/upload-csv-pool-flyover.html index 8a12cc30..21da3997 100644 --- a/html/template/sync/upload-csv-pool-bob.html +++ b/html/template/sync/upload-csv-pool-flyover.html @@ -57,7 +57,7 @@
diff --git a/html/template/sync/upload-csv-pool.html b/html/template/sync/upload-csv-pool.html index 6e28130d..c4305e87 100644 --- a/html/template/sync/upload-csv-pool.html +++ b/html/template/sync/upload-csv-pool.html @@ -56,7 +56,7 @@
Let's do this diff --git a/html/template/sync/upload-list.html b/html/template/sync/upload-list.html index 024f472a..35b912ed 100644 --- a/html/template/sync/upload-list.html +++ b/html/template/sync/upload-list.html @@ -116,7 +116,7 @@ View diff --git a/platform/csv/csv.go b/platform/csv/csv.go new file mode 100644 index 00000000..205903c8 --- /dev/null +++ b/platform/csv/csv.go @@ -0,0 +1,128 @@ +package csv + +import ( + "context" + //"encoding/csv" + "fmt" + //"io" + "strconv" + "strings" + //"sync" + //"time" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/um" + //"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/platform/geom" + //"github.com/Gleipnir-Technology/nidus-sync/platform/text" + //"github.com/Gleipnir-Technology/nidus-sync/stadia" + //"github.com/Gleipnir-Technology/nidus-sync/userfile" + "github.com/aarondl/opt/omit" + //"github.com/aarondl/opt/omitnull" + "github.com/rs/zerolog/log" +) + +type csvParserFunc[T any] = func(context.Context, bob.Tx, *models.FileuploadFile, *models.FileuploadCSV) ([]T, error) +type csvProcessorFunc[T any] = func(context.Context, bob.Tx, *models.FileuploadFile, *models.FileuploadCSV, []T) error + +func ProcessJob(ctx context.Context, file_id int32, type_ enums.FileuploadCsvtype) error { + var err error + switch type_ { + case enums.FileuploadCsvtypePoollist: + err = processCSV(ctx, file_id, parseCSVPoollist, processCSVPoollist) + case enums.FileuploadCsvtypeFlyover: + err = processCSV(ctx, file_id, parseCSVFlyover, processCSVFlyover) + } + return err +} + +func processCSV[T any](ctx context.Context, file_id int32, parser csvParserFunc[T], processor csvProcessorFunc[T]) error { + file, c, err := loadFileAndCSV(ctx, file_id) + if err != nil { + return fmt.Errorf("load file and csv: %w", err) + } + txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("Failed to start transaction: %w", err) + } + defer txn.Rollback(ctx) + parsed, err := parser(ctx, txn, file, c) + if err != nil { + return fmt.Errorf("parse file: %w", err) + } + _, err = psql.Update( + um.Table("fileupload.csv"), + um.SetCol("rowcount").ToArg(len(parsed)), + um.Where(psql.Quote("file_id").EQ(psql.Arg(file_id))), + ).Exec(ctx, txn) + if err != nil { + return fmt.Errorf("update csv row: %w", err) + } + err = processor(ctx, txn, file, c, parsed) + if err != nil { + return fmt.Errorf("process parsed file: %w", err) + } + + file.Update(ctx, txn, &models.FileuploadFileSetter{ + Status: omit.From(enums.FileuploadFilestatustypeParsed), + }) + log.Info().Int32("file.ID", file.ID).Msg("Set file to parsed") + txn.Commit(ctx) + return nil +} +func loadFileAndCSV(ctx context.Context, file_id int32) (*models.FileuploadFile, *models.FileuploadCSV, error) { + file, err := models.FindFileuploadFile(ctx, db.PGInstance.BobDB, file_id) + if err != nil { + return nil, nil, fmt.Errorf("Failed to get file %d from DB: %w", file_id, err) + } + c, err := models.FindFileuploadCSV(ctx, db.PGInstance.BobDB, file.ID) + if err != nil { + return nil, nil, fmt.Errorf("Failed to get csv file %d from DB: %w", file.ID, err) + } + return file, c, nil +} + +func addError(ctx context.Context, txn bob.Tx, c *models.FileuploadCSV, row_number int32, column_number int32, msg string) error { + r, err := models.FileuploadErrorCSVS.Insert(&models.FileuploadErrorCSVSetter{ + Col: omit.From(column_number), + CSVFileID: omit.From(c.FileID), + // ID + Line: omit.From(row_number), + Message: omit.From(msg), + }).One(ctx, txn) + if err != nil { + return fmt.Errorf("Failed to add error: %w", err) + } + log.Info().Int32("id", r.ID).Int32("file_id", c.FileID).Str("msg", msg).Int32("row", row_number).Int32("col", column_number).Msg("Created CSV file error") + return nil +} +func addImportError(file *models.FileuploadFile, err error) { + log.Debug().Err(err).Int32("file_id", file.ID).Msg("Fake add import error") +} +func parseBool(s string) (bool, error) { + sl := strings.ToLower(s) + boolValue, err := strconv.ParseBool(sl) + if err != nil { + // Handle some of the stuff that strconv doesn't handle + switch sl { + case "yes": + return true, nil + case "no": + return false, nil + default: + return false, fmt.Errorf("unrecognized '%s'", sl) + } + + } + return boolValue, err +} + +func errorMissingHeader(ctx context.Context, txn bob.Tx, c *models.FileuploadCSV, h headerPoolEnum) error { + msg := fmt.Sprintf("The file is missing the '%s' header", h.String()) + return addError(ctx, txn, c, 0, 0, msg) +} diff --git a/platform/csv/flyover.go b/platform/csv/flyover.go new file mode 100644 index 00000000..a51fa032 --- /dev/null +++ b/platform/csv/flyover.go @@ -0,0 +1,307 @@ +package csv + +import ( + "context" + "encoding/csv" + "fmt" + "io" + "strconv" + "strings" + "time" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/um" + "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/platform/geom" + "github.com/Gleipnir-Technology/nidus-sync/platform/text" + "github.com/Gleipnir-Technology/nidus-sync/userfile" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/rs/zerolog/log" +) + +type Enum interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~string +} + +type headerFlyoverEnum int + +const ( + headerFlyoverComment headerFlyoverEnum = iota + headerFlyoverLatitude + headerFlyoverLongitude + headerFlyoverNone +) + +func (e headerFlyoverEnum) String() string { + switch e { + case headerFlyoverComment: + return "Comment" + case headerFlyoverLatitude: + return "TargetLat" + case headerFlyoverLongitude: + return "TargetLon" + default: + return "bad programmer" + } +} + +var parseCSVFlyover = makeParseCSV( + makeParseHeaders(map[string]headerFlyoverEnum{ + "comment": headerFlyoverComment, + "targetlat": headerFlyoverLatitude, + "targetlon": headerFlyoverLongitude, + "*": headerFlyoverNone, + }), + insertFlyover, +) + +type insertModelFunc[ModelType any, HeaderType Enum] = func(context.Context, bob.Tx, *models.FileuploadFile, *models.FileuploadCSV, int32, []HeaderType, []string, []string) (ModelType, error) +type parseCSVFunc[ModelType any] = func(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV) ([]ModelType, error) + +func makeParseCSV[ModelType any, HeaderType Enum](parseHeader parseHeaderFunc[HeaderType], insertModel insertModelFunc[ModelType, HeaderType]) parseCSVFunc[ModelType] { + return func(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV) ([]ModelType, error) { + rows := make([]ModelType, 0) + r, err := userfile.NewFileReader(userfile.CollectionCSV, file.FileUUID) + if err != nil { + return rows, fmt.Errorf("Failed to get filereader for %d: %w", file.ID, err) + } + reader := csv.NewReader(r) + h, err := reader.Read() + if err != nil { + return rows, fmt.Errorf("Failed to read header of CSV for file %d: %w", file.ID, err) + } + header_types, header_names := parseHeader(h) + /* + TODO: Add support for missing headersi + missing_headers := missingRequiredHeaders(header_types) + for _, mh := range missing_headers { + errorMissingHeader(ctx, txn, c, mh) + file.Update(ctx, txn, &models.FileuploadFileSetter{ + Status: omit.From(enums.FileuploadFilestatustypeError), + }) + return pools, nil + } + */ + // Start at 2 because the header is line 1, not line 0 + line_number := int32(2) + for { + row, err := reader.Read() + if err != nil { + if err == io.EOF { + return rows, nil + } + return rows, fmt.Errorf("Failed to read all CSV records for file %d: %w", file.ID, err) + } + m, err := insertModel(ctx, txn, file, c, line_number, header_types, header_names, row) + rows = append(rows, m) + line_number = line_number + 1 + } + } +} +func insertFlyover(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV, line_number int32, header_types []headerFlyoverEnum, header_names []string, row []string) (*models.FileuploadFlyoverAerialService, error) { + setter := models.FileuploadFlyoverAerialServiceSetter{ + Committed: omit.From(false), + Condition: omit.From(enums.FileuploadPoolconditiontypeUnknown), + Created: omit.From(time.Now()), + CreatorID: omit.From(file.CreatorID), + CSVFile: omit.From(file.ID), + Deleted: omitnull.FromPtr[time.Time](nil), + Geom: omitnull.FromPtr[string](nil), + H3cell: omitnull.FromPtr[string](nil), + // ID - generated + OrganizationID: omit.From(file.OrganizationID), + } + var lat, lng float64 + var err error + for i, value := range row { + if value == "" { + continue + } + header_type := header_types[i] + switch header_type { + case headerFlyoverComment: + condition, err := parsePoolCondition(value) + if err == nil { + setter.Condition = omit.From(condition) + } else { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not a pool condition that we recognize. It should be one of %s", value, poolConditionValidValues())) + continue + } + case headerFlyoverLatitude: + lat, err = strconv.ParseFloat(value, 10) + if err != nil { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not decimal value", value)) + continue + } + case headerFlyoverLongitude: + lng, err = strconv.ParseFloat(value, 10) + if err != nil { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not decimal value", value)) + continue + } + } + } + flyover, err := models.FileuploadFlyoverAerialServices.Insert(&setter).One(ctx, txn) + if err != nil { + return nil, fmt.Errorf("Failed to create flyover: %w", err) + } + cell, err := h3utils.GetCell(lng, lat, 15) + if err != nil { + return nil, fmt.Errorf("failed to convert lat %f lng %f to h3 cell", lng, lat) + } + geom_query := geom.PostgisPointQuery(lng, lat) + _, err = psql.Update( + um.Table("fileupload.flyover_aerial_service"), + um.SetCol("h3cell").ToArg(cell), + um.SetCol("geom").To(geom_query), + um.Where(psql.Quote("id").EQ(psql.Arg(flyover.ID))), + ).Exec(ctx, txn) + if err != nil { + return nil, fmt.Errorf("failed to update flyover geometry: %w", err) + } + return flyover, nil +} +func insertPoollistRow(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV, line_number int32, header_types []headerPoolEnum, header_names []string, row []string) (*models.FileuploadPool, error) { + tags := make(map[string]string, 0) + // Start with a setter with default values, comment out the required fields to ensure they're set + setter := models.FileuploadPoolSetter{ + // AddressCity: omit.From(), + // AddressPostalCode: omit.From(), + // AddressStreet: omit.From(), + Committed: omit.From(false), + Condition: omit.From(enums.FileuploadPoolconditiontypeUnknown), + Created: omit.From(time.Now()), + CreatorID: omit.From(file.CreatorID), + CSVFile: omit.From(file.ID), + Deleted: omitnull.FromPtr[time.Time](nil), + Geom: omitnull.FromPtr[string](nil), + H3cell: omitnull.FromPtr[string](nil), + // ID - generated + IsInDistrict: omit.From(false), + IsNew: omit.From(true), + LineNumber: omit.From(line_number), + Notes: omit.From(""), + OrganizationID: omit.From(file.OrganizationID), + PropertyOwnerName: omit.From(""), + PropertyOwnerPhoneE164: omitnull.FromPtr[string](nil), + ResidentOwned: omitnull.FromPtr[bool](nil), + ResidentPhoneE164: omitnull.FromPtr[string](nil), + // Can't set this via a Setter + // Tags: convertToPGData(tags), + } + for i, value := range row { + if value == "" { + continue + } + header_type := header_types[i] + switch header_type { + case headerAddressCity: + setter.AddressCity = omit.From(value) + case headerAddressPostalCode: + setter.AddressPostalCode = omit.From(value) + case headerAddressStreet: + setter.AddressStreet = omit.From(value) + case headerCondition: + condition, err := parsePoolCondition(value) + if err == nil { + setter.Condition = omit.From(condition) + } else { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not a pool condition that we recognize. It should be one of %s", value, poolConditionValidValues())) + continue + } + case headerNotes: + setter.Notes = omit.From(value) + case headerPropertyOwnerName: + setter.PropertyOwnerName = omit.From(value) + case headerPropertyOwnerPhone: + phone, err := text.ParsePhoneNumber(value) + if err != nil { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not a phone number that we recognize. Ideally it should be of the form '+12223334444'", value)) + continue + } + text.EnsureInDB(ctx, txn, *phone) + setter.PropertyOwnerPhoneE164 = omitnull.From(text.PhoneString(*phone)) + case headerResidentOwned: + boolValue, err := parseBool(value) + if err != nil { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not something that we recognize as a true/false value. Please use either 'true' or 'false'", value)) + continue + } + setter.ResidentOwned = omitnull.From(boolValue) + case headerResidentPhone: + phone, err := text.ParsePhoneNumber(value) + if err != nil { + addError(ctx, txn, c, int32(line_number), int32(i), fmt.Sprintf("'%s' is not a phone number that we recognize. Ideally it should be of the form '+12223334444'", value)) + continue + } + text.EnsureInDB(ctx, txn, *phone) + setter.ResidentPhoneE164 = omitnull.From(text.PhoneString(*phone)) + case headerTag: + tags[header_names[i]] = value + } + + } + setter.Tags = omit.From(db.ConvertToPGData(tags)) + return models.FileuploadPools.Insert(&setter).One(ctx, txn) +} + +type parseHeaderFunc[EnumType any] = func(row []string) ([]EnumType, []string) + +func makeParseHeaders[EnumType any](headerToType map[string]EnumType) parseHeaderFunc[EnumType] { + return func(row []string) ([]EnumType, []string) { + result_enums := make([]EnumType, len(row)) + result_names := make([]string, len(row)) + for i, h := range row { + ht := strings.TrimSpace(h) + hl := strings.ToLower(ht) + log.Debug().Str("header", hl).Msg("Saw CSV header") + var type_ EnumType + type_, ok := headerToType[hl] + if !ok { + // See if there is a '*' entry which should match anything + all_type, ok2 := headerToType["*"] + if !ok2 { + log.Error().Str("name", hl).Msg("No header type matches column. You should add a '*' to the makeParseHeaders call") + continue + } else { + type_ = all_type + } + } + result_enums[i] = type_ + result_names[i] = hl + } + + return result_enums, result_names + } +} + +func processCSVFlyover(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV, rows []*models.FileuploadFlyoverAerialService) error { + return nil +} + +var poolConditionAliases = map[string]string{ + "covered": "unknown", + "dark bottom": "unknown", + "no data": "unknown", + "empty": "dry", + "green": "green", + "murky pool": "murky", + "putting green": "false pool", + "questionable": "unknown", +} + +func parsePoolCondition(c string) (enums.FileuploadPoolconditiontype, error) { + var condition enums.FileuploadPoolconditiontype + col_l := strings.ToLower(c) + col_translated, ok := poolConditionAliases[col_l] + if ok { + col_l = col_translated + } + err := condition.Scan(col_l) + return condition, err +} diff --git a/platform/csv/pool.go b/platform/csv/pool.go index 91ec0828..f0a700d4 100644 --- a/platform/csv/pool.go +++ b/platform/csv/pool.go @@ -5,7 +5,6 @@ import ( "encoding/csv" "fmt" "io" - "strconv" "strings" "sync" "time" @@ -66,47 +65,6 @@ func (e headerPoolEnum) String() string { return "bad programmer" } } -func ProcessJob(ctx context.Context, file_id int32) error { - file, err := models.FindFileuploadFile(ctx, db.PGInstance.BobDB, file_id) - if err != nil { - return fmt.Errorf("Failed to get file %d from DB: %w", file_id, err) - } - txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil) - if err != nil { - return fmt.Errorf("Failed to start transaction: %w", err) - } - defer txn.Rollback(ctx) - c, err := models.FindFileuploadCSV(ctx, txn, file.ID) - if err != nil { - return fmt.Errorf("Failed to get csv file %d from DB: %w", file.ID, err) - } - pools, err := parseFile(ctx, txn, file, c) - if err != nil { - return fmt.Errorf("parse file: %w", err) - } - _, err = psql.Update( - um.Table("fileupload.csv"), - um.SetCol("rowcount").ToArg(len(pools)), - um.Where(psql.Quote("file_id").EQ(psql.Arg(file_id))), - ).Exec(ctx, txn) - if err != nil { - return fmt.Errorf("update csv row: %w", err) - } - org, err := models.FindOrganization(ctx, db.PGInstance.BobDB, file.OrganizationID) - if err != nil { - return fmt.Errorf("get org: %w", err) - } - err = bulkGeocode(ctx, txn, file, c, pools, org) - if err != nil { - log.Error().Err(err).Msg("Failure during geocoding") - } - file.Update(ctx, txn, &models.FileuploadFileSetter{ - Status: omit.From(enums.FileuploadFilestatustypeParsed), - }) - log.Info().Int32("file.ID", file.ID).Msg("Set file to parsed") - txn.Commit(ctx) - return nil -} func bulkGeocode(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV, pools []*models.FileuploadPool, org *models.Organization) error { if len(pools) == 0 { return nil @@ -215,7 +173,7 @@ func geocode(ctx context.Context, txn bob.Tx, client *stadia.StadiaMaps, job *jo } return nil } -func parseFile(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV) ([]*models.FileuploadPool, error) { +func parseCSVPoollist(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV) ([]*models.FileuploadPool, error) { pools := make([]*models.FileuploadPool, 0) r, err := userfile.NewFileReader(userfile.CollectionCSV, file.FileUUID) if err != nil { @@ -339,45 +297,18 @@ func parseFile(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c * line_number = line_number + 1 } } -func addError(ctx context.Context, txn bob.Tx, c *models.FileuploadCSV, row_number int32, column_number int32, msg string) error { - r, err := models.FileuploadErrorCSVS.Insert(&models.FileuploadErrorCSVSetter{ - Col: omit.From(column_number), - CSVFileID: omit.From(c.FileID), - // ID - Line: omit.From(row_number), - Message: omit.From(msg), - }).One(ctx, txn) +func processCSVPoollist(ctx context.Context, txn bob.Tx, file *models.FileuploadFile, c *models.FileuploadCSV, parsed []*models.FileuploadPool) error { + org, err := models.FindOrganization(ctx, db.PGInstance.BobDB, file.OrganizationID) if err != nil { - return fmt.Errorf("Failed to add error: %w", err) + return fmt.Errorf("get org: %w", err) + } + err = bulkGeocode(ctx, txn, file, c, parsed, org) + if err != nil { + log.Error().Err(err).Msg("Failure during geocoding") } - log.Info().Int32("id", r.ID).Int32("file_id", c.FileID).Str("msg", msg).Int32("row", row_number).Int32("col", column_number).Msg("Created CSV file error") return nil } -func addImportError(file *models.FileuploadFile, err error) { - log.Debug().Err(err).Int32("file_id", file.ID).Msg("Fake add import error") -} -func parseBool(s string) (bool, error) { - sl := strings.ToLower(s) - boolValue, err := strconv.ParseBool(sl) - if err != nil { - // Handle some of the stuff that strconv doesn't handle - switch sl { - case "yes": - return true, nil - case "no": - return false, nil - default: - return false, fmt.Errorf("unrecognized '%s'", sl) - } - } - return boolValue, err -} - -func errorMissingHeader(ctx context.Context, txn bob.Tx, c *models.FileuploadCSV, h headerPoolEnum) error { - msg := fmt.Sprintf("The file is missing the '%s' header", h.String()) - return addError(ctx, txn, c, 0, 0, msg) -} func maybeAddServiceArea(req *stadia.StructuredGeocodeRequest, org *models.Organization) { /* if org.ServiceAreaXmax.IsNull() || diff --git a/platform/pdf/pdf.go b/platform/pdf/pdf.go new file mode 100644 index 00000000..3d1b753f --- /dev/null +++ b/platform/pdf/pdf.go @@ -0,0 +1,42 @@ +package pdf + +import ( + "context" + "fmt" + + "github.com/Gleipnir-Technology/nidus-sync/config" + "github.com/chromedp/cdproto/page" + "github.com/chromedp/chromedp" + "github.com/rs/zerolog/log" +) + +func GeneratePDF(ctx context.Context, code string) ([]byte, error) { + // create context + chrome_ctx, cancel := chromedp.NewContext(context.Background()) + defer cancel() + + // capture pdf + var buf []byte + url := fmt.Sprintf("http://%s/mailer/%s/preview", config.Bind, code) + log.Info().Str("url", url).Msg("Getting with headless chrome") + if err := chromedp.Run(chrome_ctx, printToPDF(url, &buf)); err != nil { + return nil, fmt.Errorf("print to pdf: %w", err) + } + + return buf, nil +} + +// print a specific pdf page. +func printToPDF(urlstr string, res *[]byte) chromedp.Tasks { + return chromedp.Tasks{ + chromedp.Navigate(urlstr), + chromedp.ActionFunc(func(ctx context.Context) error { + buf, _, err := page.PrintToPDF().WithPrintBackground(false).Do(ctx) + if err != nil { + return err + } + *res = buf + return nil + }), + } +} diff --git a/platform/pool.go b/platform/pool.go index 372e73f9..c19713fa 100644 --- a/platform/pool.go +++ b/platform/pool.go @@ -44,16 +44,16 @@ type UploadPoolRow struct { Street string Tags map[string]string } -type PoolUpload struct { +type Upload struct { Created time.Time `db:"created"` ID int32 `db:"id"` Status string `db:"status"` } -func NewPoolUpload(ctx context.Context, u *models.User, upload userfile.FileUpload) (PoolUpload, error) { +func NewUpload(ctx context.Context, u *models.User, upload userfile.FileUpload, t enums.FileuploadCsvtype) (Upload, error) { txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil) if err != nil { - return PoolUpload{}, fmt.Errorf("Failed to begin transaction: %w", err) + return Upload{}, fmt.Errorf("Failed to begin transaction: %w", err) } defer txn.Rollback(ctx) @@ -69,21 +69,21 @@ func NewPoolUpload(ctx context.Context, u *models.User, upload userfile.FileUplo FileUUID: omit.From(upload.UUID), }).One(ctx, txn) if err != nil { - return PoolUpload{}, fmt.Errorf("Failed to create file upload: %w", err) + return Upload{}, fmt.Errorf("Failed to create file upload: %w", err) } _, err = models.FileuploadCSVS.Insert(&models.FileuploadCSVSetter{ Committed: omitnull.FromPtr[time.Time](nil), FileID: omit.From(file.ID), Rowcount: omit.From(int32(0)), - Type: omit.From(enums.FileuploadCsvtypePoollist), + Type: omit.From(t), }).One(ctx, txn) if err != nil { - return PoolUpload{}, fmt.Errorf("Failed to create csv: %w", err) + return Upload{}, fmt.Errorf("Failed to create csv: %w", err) } log.Info().Int32("id", file.ID).Msg("Created new pool CSV upload") txn.Commit(ctx) - background.ProcessUpload(file.ID) - return PoolUpload{ + background.ProcessUpload(file.ID, t) + return Upload{ ID: file.ID, }, nil } @@ -115,7 +115,7 @@ func GetUploadPoolDetail(ctx context.Context, organization_id int32, file_id int if row.Line == 0 { file_errors = append(file_errors, e) } else { - log.Info().Int32("line", row.Line).Msg("Found error") + //log.Info().Int32("line", row.Line).Msg("Found error") by_line, ok := errors_by_line[row.Line] if !ok { errors_by_line[row.Line] = []UploadPoolError{e} @@ -175,8 +175,8 @@ func GetUploadPoolDetail(ctx context.Context, organization_id int32, file_id int Status: file.Status.String(), }, nil } -func PoolUploadList(ctx context.Context, organization_id int32) ([]PoolUpload, error) { - results := make([]PoolUpload, 0) +func PoolUploadList(ctx context.Context, organization_id int32) ([]Upload, error) { + results := make([]Upload, 0) rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( sm.Columns( // fileupload.csv columns @@ -200,7 +200,7 @@ func PoolUploadList(ctx context.Context, organization_id int32) ([]PoolUpload, e sm.From("fileupload.csv").As("csv"), sm.InnerJoin("fileupload.file").As("file").OnEQ(psql.Raw("csv.file_id"), psql.Raw("file.id")), sm.Where(psql.Raw("file.organization_id").EQ(psql.Arg(organization_id))), - ), scan.StructMapper[PoolUpload]()) + ), scan.StructMapper[Upload]()) if err != nil { return results, fmt.Errorf("Failed to query pool upload rows: %w", err) } diff --git a/platform/upload.go b/platform/upload.go index 765ca898..166db833 100644 --- a/platform/upload.go +++ b/platform/upload.go @@ -35,6 +35,9 @@ type UploadSummary struct { Type string `db:"type"` } +func UploadCommit(ctx context.Context, org *models.Organization, file_id int32) error { + return nil +} func UploadDiscard(ctx context.Context, org *models.Organization, file_id int32) error { _, err := psql.Update( um.Table(models.FileuploadFiles.Alias()), diff --git a/sync/mailer.go b/sync/mailer.go index dd57bc0c..40194780 100644 --- a/sync/mailer.go +++ b/sync/mailer.go @@ -1,14 +1,16 @@ package sync import ( + "bytes" + "fmt" + "io" "net/http" - //"strconv" "github.com/Gleipnir-Technology/nidus-sync/config" "github.com/Gleipnir-Technology/nidus-sync/db" "github.com/Gleipnir-Technology/nidus-sync/db/models" "github.com/Gleipnir-Technology/nidus-sync/html" - //"github.com/google/uuid" + "github.com/Gleipnir-Technology/nidus-sync/platform/pdf" "github.com/go-chi/chi/v5" ) @@ -22,8 +24,26 @@ type contentMailer struct { ReportURL string } -// func getMailer(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentMailer], *errorWithStatus) { func getMailer(w http.ResponseWriter, r *http.Request) { + code := chi.URLParam(r, "code") + if code == "" { + http.Error(w, "empty code", http.StatusBadRequest) + return + } + + content, err := pdf.GeneratePDF(r.Context(), code) + if err != nil { + respondError(w, "generate pdf failure", err, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/pdf") + disposition := fmt.Sprintf("attachment; filename=\"compliance-mailer-%s.pdf\"", code) + w.Header().Set("Content-Disposition", disposition) + _, err = io.Copy(w, bytes.NewReader(content)) + if err != nil { + respondError(w, "copy error", err, http.StatusInternalServerError) + return + } } func getMailerPreview(w http.ResponseWriter, r *http.Request) { code := chi.URLParam(r, "code") diff --git a/sync/routes.go b/sync/routes.go index 43af57f5..6a54ffc8 100644 --- a/sync/routes.go +++ b/sync/routes.go @@ -60,11 +60,12 @@ func Router() chi.Router { r.Method("GET", "/configuration/pesticide/add", authenticatedHandler(getConfigurationPesticideAdd)) r.Method("GET", "/configuration/upload", authenticatedHandler(getUploadList)) r.Method("GET", "/configuration/upload/pool", authenticatedHandler(getUploadPool)) - r.Method("GET", "/configuration/upload/pool/bob", authenticatedHandler(getUploadPoolBobCreate)) - r.Method("POST", "/configuration/upload/pool/bob", authenticatedHandlerPostMultipart(postUploadPoolBobCreate)) + r.Method("GET", "/configuration/upload/pool/flyover", authenticatedHandler(getUploadPoolFlyoverCreate)) + r.Method("POST", "/configuration/upload/pool/flyover", authenticatedHandlerPostMultipart(postUploadPoolFlyoverCreate)) r.Method("GET", "/configuration/upload/pool/custom", authenticatedHandler(getUploadPoolCustomCreate)) r.Method("POST", "/configuration/upload/pool/custom", authenticatedHandlerPostMultipart(postUploadPoolCustomCreate)) r.Method("GET", "/configuration/upload/{id}", authenticatedHandler(getUploadByID)) + r.Method("POST", "/configuration/upload/{id}/commit", authenticatedHandlerPost(postUploadCommit)) r.Method("POST", "/configuration/upload/{id}/discard", authenticatedHandlerPost(postUploadDiscard)) r.Method("GET", "/configuration/user", authenticatedHandler(getConfigurationUserList)) r.Method("GET", "/configuration/user/add", authenticatedHandler(getConfigurationUserAdd)) diff --git a/sync/upload.go b/sync/upload.go index c8eaaac2..47cd7cad 100644 --- a/sync/upload.go +++ b/sync/upload.go @@ -6,11 +6,12 @@ import ( "net/http" "strconv" - "github.com/Gleipnir-Technology/nidus-sync/config" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" "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/rs/zerolog/log" ) type contentUploadList struct { @@ -25,25 +26,13 @@ func getUploadList(ctx context.Context, r *http.Request, org *models.Organizatio }), newErrorMaybe("get upload list: %w", err) } -type contentUploadURL struct { - Discard string // URL for discarding the upload -} - -func newContentUploadURL(id int32) contentUploadURL { - id_str := strconv.FormatInt(int64(id), 10) - return contentUploadURL{ - Discard: config.MakeURLNidus("/upload/%s/discard", id_str), - } -} - type contentUploadDetail struct { CSVFileID int32 Organization *models.Organization Upload platform.UploadPoolDetail - URL contentUploadURL } type contentUploadPoolList struct { - Uploads []platform.PoolUpload + Uploads []platform.Upload } type contentUploadPool struct{} @@ -52,11 +41,11 @@ func getUploadPool(ctx context.Context, r *http.Request, org *models.Organizatio return newResponse("sync/upload-csv-pool.html", data), nil } -type contentUploadPoolBobCreate struct{} +type contentUploadPoolFlyoverCreate struct{} -func getUploadPoolBobCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadPoolBobCreate], *errorWithStatus) { - data := contentUploadPoolBobCreate{} - return newResponse("sync/upload-csv-pool-bob.html", data), nil +func getUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadPoolFlyoverCreate], *errorWithStatus) { + data := contentUploadPoolFlyoverCreate{} + return newResponse("sync/upload-csv-pool-flyover.html", data), nil } type contentUploadPoolCustomCreate struct{} @@ -66,6 +55,8 @@ func getUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models return newResponse("sync/upload-csv-pool-custom.html", data), nil } func getUploadByID(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadDetail], *errorWithStatus) { + test := newContentURLUpload() + log.Info().Str("output", test.Discard(123)).Send() file_id_str := chi.URLParam(r, "id") file_id_, err := strconv.ParseInt(file_id_str, 10, 32) if err != nil { @@ -80,11 +71,25 @@ func getUploadByID(ctx context.Context, r *http.Request, org *models.Organizatio CSVFileID: file_id, Organization: org, Upload: detail, - URL: newContentUploadURL(file_id), } return newResponse("sync/upload-by-id.html", data), nil } +type FormUploadCommit struct{} + +func postUploadCommit(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadCommit) (string, *errorWithStatus) { + file_id_str := chi.URLParam(r, "id") + file_id_, err := strconv.ParseInt(file_id_str, 10, 32) + if err != nil { + return "", newError("Failed to parse file_id: %w", err) + } + err = platform.UploadCommit(ctx, org, int32(file_id_)) + if err != nil { + return "", newError("Failed to mark discarded: %w", err) + } + return "/configuration/upload", nil +} + type FormUploadDiscard struct{} func postUploadDiscard(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadDiscard) (string, *errorWithStatus) { @@ -97,13 +102,28 @@ func postUploadDiscard(ctx context.Context, r *http.Request, org *models.Organiz if err != nil { return "", newError("Failed to mark discarded: %w", err) } - return "/upload", nil + return "/configuration/upload", nil } type FormUploadPool struct{} -func postUploadPoolBobCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *errorWithStatus) { - return "", nil +func postUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *errorWithStatus) { + uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV) + if err != nil { + return "", newError("Failed to extract image uploads: %s", err) + } + if len(uploads) == 0 { + return "", newErrorStatus(http.StatusBadRequest, "No upload found") + } + if len(uploads) != 1 { + return "", newErrorStatus(http.StatusBadRequest, "You must only submit one file at a time") + } + upload := uploads[0] + saved_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypeFlyover) + if err != nil { + return "", newError("Failed to create new pool: %w", err) + } + return fmt.Sprintf("/configuration/upload/%d", saved_upload.ID), nil } func postUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *errorWithStatus) { uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV) @@ -117,9 +137,9 @@ func postUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *model return "", newErrorStatus(http.StatusBadRequest, "You must only submit one file at a time") } upload := uploads[0] - pool_upload, err := platform.NewPoolUpload(r.Context(), u, upload) + pool_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypePoollist) if err != nil { return "", newError("Failed to create new pool: %w", err) } - return fmt.Sprintf("/upload/%d", pool_upload.ID), nil + return fmt.Sprintf("/configuration/upload/%d", pool_upload.ID), nil } diff --git a/sync/url.go b/sync/url.go index 8b80126b..bfbd13d1 100644 --- a/sync/url.go +++ b/sync/url.go @@ -1,6 +1,8 @@ package sync import ( + "strconv" + "github.com/Gleipnir-Technology/nidus-sync/config" ) @@ -74,17 +76,29 @@ func newContentURLSidebar() contentURLSidebar { } } +type urlForID = func(int) string + +func makeURLForID(pattern string) urlForID { + return func(id int) string { + return config.MakeURLNidus(pattern, strconv.Itoa(id)) + } +} + type contentURLUpload struct { + Commit urlForID + Discard urlForID Pool string - PoolBob string PoolCustom string + PoolFlyover string SamplePoolCSV string } func newContentURLUpload() contentURLUpload { return contentURLUpload{ + Commit: makeURLForID("/configuration/upload/%s/commit"), + Discard: makeURLForID("/configuration/upload/%s/discard"), Pool: config.MakeURLNidus("/configuration/upload/pool"), - PoolBob: config.MakeURLNidus("/configuration/upload/pool/bob"), + PoolFlyover: config.MakeURLNidus("/configuration/upload/pool/flyover"), PoolCustom: config.MakeURLNidus("/configuration/upload/pool/custom"), SamplePoolCSV: config.MakeURLNidus("/static/file/sample-pool.csv"), } diff --git a/tools/insert-compliance-report-request.sql b/tools/insert-compliance-report-request.sql index 3cf87317..fbd18bb7 100644 --- a/tools/insert-compliance-report-request.sql +++ b/tools/insert-compliance-report-request.sql @@ -1,3 +1,12 @@ INSERT INTO compliance_report_request(created, creator, id, public_id, site_id, site_version) VALUES (NOW(), :user_id, DEFAULT, :public_id, :site_id, 1); + +-- INSERT INTO compliance_report_request (created, creator, public_id, site_id, site_version) +-- SELECT + -- NOW(), + -- 1, + -- generate_alphanumeric_code(8), + -- id, + -- version +-- FROM site; diff --git a/tools/insert-site-from-upload.sql b/tools/insert-site-from-upload.sql new file mode 100644 index 00000000..3c1fb910 --- /dev/null +++ b/tools/insert-site-from-upload.sql @@ -0,0 +1,40 @@ +-- This query is just a one-off to quickly get uploaded data turned into sites. +INSERT INTO site ( + address_id, + created, + creator_id, + notes, + organization_id, + owner_name, + parcel_id, + tags, + version +) +SELECT DISTINCT ON (closest_address.id) + closest_address.id AS address_id, + fas.created, + fas.creator_id, + '' AS notes, + fas.organization_id, + '' AS owner_name, + containing_parcel.id AS parcel_id, + ''::hstore AS tags, + 1 AS version +FROM fileupload.flyover_aerial_service fas +CROSS JOIN LATERAL ( + SELECT a.id + FROM address a + ORDER BY a.geom <-> fas.geom + LIMIT 1 +) closest_address +CROSS JOIN LATERAL ( + SELECT p.id + FROM parcel p + WHERE ST_Contains(p.geometry, fas.geom) + LIMIT 1 +) containing_parcel +WHERE fas.geom IS NOT NULL + AND fas.deleted IS NULL +ORDER BY closest_address.id, fas.created ASC -- Keep the earliest created per address +ON CONFLICT (address_id) DO NOTHING; -- Skip if address already has a site +