From e7ece52c8cf81a5b671e0821685a69430f74a036 Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Thu, 20 Nov 2025 20:59:28 +0000 Subject: [PATCH] Add trap count data to source page It's...way too many rows, now that I have the actual data. It needs to be reworked. --- dbinfo/fs_mosquitoinspection.bob.go | 34 ++- dbinfo/fs_pointlocation.bob.go | 34 ++- dbinfo/fs_traplocation.bob.go | 34 ++- dbinfo/fs_treatment.bob.go | 34 ++- dbinfo/h3_aggregation.bob.go | 42 ++-- factory/bobfactory_main.bob.go | 9 +- factory/fs_mosquitoinspection.bob.go | 62 +++++ factory/fs_pointlocation.bob.go | 62 +++++ factory/fs_traplocation.bob.go | 62 +++++ factory/fs_treatment.bob.go | 62 +++++ factory/h3_aggregation.bob.go | 236 +++++++++++------- fieldseeker.go | 15 ++ go.mod | 2 +- go.sum | 4 +- html.go | 64 +++-- migrations/00015_fs_geometry.sql | 27 ++- model_conversion.go | 277 +++++++++++++++++++--- models/fs_mosquitoinspection.bob.go | 33 ++- models/fs_pointlocation.bob.go | 33 ++- models/fs_traplocation.bob.go | 33 ++- models/fs_treatment.bob.go | 33 ++- models/h3_aggregation.bob.go | 115 +++++---- sql/test_utils.bob_test.go | 40 ++++ sql/trapcount_by_location_id.bob.go | 114 +++++++++ sql/trapcount_by_location_id.bob.sql | 19 ++ sql/trapcount_by_location_id.bob_test.go | 111 +++++++++ sql/trapcount_by_location_id.sql | 17 ++ sql/traplocation_by_source_id.bob.go | 106 +++++++++ sql/traplocation_by_source_id.bob.sql | 17 ++ sql/traplocation_by_source_id.bob_test.go | 99 ++++++++ sql/traplocation_by_source_id.sql | 14 ++ templates/source.html | 76 ++---- 32 files changed, 1622 insertions(+), 298 deletions(-) create mode 100644 fieldseeker.go create mode 100644 sql/trapcount_by_location_id.bob.go create mode 100644 sql/trapcount_by_location_id.bob.sql create mode 100644 sql/trapcount_by_location_id.bob_test.go create mode 100644 sql/trapcount_by_location_id.sql create mode 100644 sql/traplocation_by_source_id.bob.go create mode 100644 sql/traplocation_by_source_id.bob.sql create mode 100644 sql/traplocation_by_source_id.bob_test.go create mode 100644 sql/traplocation_by_source_id.sql diff --git a/dbinfo/fs_mosquitoinspection.bob.go b/dbinfo/fs_mosquitoinspection.bob.go index b691c8d8..7f1ff0c7 100644 --- a/dbinfo/fs_mosquitoinspection.bob.go +++ b/dbinfo/fs_mosquitoinspection.bob.go @@ -564,6 +564,15 @@ var FSMosquitoinspections = Table[ Generated: false, AutoIncr: false, }, + Geom: column{ + Name: "geom", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: fsMosquitoinspectionIndexes{ FSMosquitoinspectionPkey: index{ @@ -583,6 +592,23 @@ var FSMosquitoinspections = Table[ Where: "", Include: []string{}, }, + IdxFSMosquitoinspectionGeom: index{ + Type: "gist", + Name: "idx_fs_mosquitoinspection_geom", + Columns: []indexColumn{ + { + Name: "geom", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: false, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, }, PrimaryKey: &constraint{ Name: "fs_mosquitoinspection_pkey", @@ -666,21 +692,23 @@ type fsMosquitoinspectionColumns struct { Adminaction column Ptaid column Updated column + Geom column } func (c fsMosquitoinspectionColumns) AsSlice() []column { return []column{ - c.OrganizationID, c.Actiontaken, c.Activity, c.Adultact, c.Avetemp, c.Avglarvae, c.Avgpupae, c.Breeding, c.Cbcount, c.Comments, c.Containercount, c.Creationdate, c.Creator, c.Domstage, c.Eggs, c.Enddatetime, c.Editdate, c.Editor, c.Fieldspecies, c.Fieldtech, c.Globalid, c.Jurisdiction, c.Larvaepresent, c.Linelocid, c.Locationname, c.Lstages, c.Numdips, c.Objectid, c.Personalcontact, c.Pointlocid, c.Polygonlocid, c.Posdips, c.Positivecontainercount, c.Pupaepresent, c.Raingauge, c.Recordstatus, c.Reviewed, c.Reviewedby, c.Revieweddate, c.Sdid, c.Sitecond, c.Srid, c.Startdatetime, c.Tirecount, c.Totlarvae, c.Totpupae, c.Visualmonitoring, c.Vmcomments, c.Winddir, c.Windspeed, c.Zone, c.Zone2, c.CreatedDate, c.CreatedUser, c.GeometryX, c.GeometryY, c.LastEditedDate, c.LastEditedUser, c.Adminaction, c.Ptaid, c.Updated, + c.OrganizationID, c.Actiontaken, c.Activity, c.Adultact, c.Avetemp, c.Avglarvae, c.Avgpupae, c.Breeding, c.Cbcount, c.Comments, c.Containercount, c.Creationdate, c.Creator, c.Domstage, c.Eggs, c.Enddatetime, c.Editdate, c.Editor, c.Fieldspecies, c.Fieldtech, c.Globalid, c.Jurisdiction, c.Larvaepresent, c.Linelocid, c.Locationname, c.Lstages, c.Numdips, c.Objectid, c.Personalcontact, c.Pointlocid, c.Polygonlocid, c.Posdips, c.Positivecontainercount, c.Pupaepresent, c.Raingauge, c.Recordstatus, c.Reviewed, c.Reviewedby, c.Revieweddate, c.Sdid, c.Sitecond, c.Srid, c.Startdatetime, c.Tirecount, c.Totlarvae, c.Totpupae, c.Visualmonitoring, c.Vmcomments, c.Winddir, c.Windspeed, c.Zone, c.Zone2, c.CreatedDate, c.CreatedUser, c.GeometryX, c.GeometryY, c.LastEditedDate, c.LastEditedUser, c.Adminaction, c.Ptaid, c.Updated, c.Geom, } } type fsMosquitoinspectionIndexes struct { - FSMosquitoinspectionPkey index + FSMosquitoinspectionPkey index + IdxFSMosquitoinspectionGeom index } func (i fsMosquitoinspectionIndexes) AsSlice() []index { return []index{ - i.FSMosquitoinspectionPkey, + i.FSMosquitoinspectionPkey, i.IdxFSMosquitoinspectionGeom, } } diff --git a/dbinfo/fs_pointlocation.bob.go b/dbinfo/fs_pointlocation.bob.go index c5969b8d..667d46ae 100644 --- a/dbinfo/fs_pointlocation.bob.go +++ b/dbinfo/fs_pointlocation.bob.go @@ -447,6 +447,15 @@ var FSPointlocations = Table[ Generated: false, AutoIncr: false, }, + Geom: column{ + Name: "geom", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: fsPointlocationIndexes{ FSPointlocationPkey: index{ @@ -466,6 +475,23 @@ var FSPointlocations = Table[ Where: "", Include: []string{}, }, + IdxFSPointlocationGeom: index{ + Type: "gist", + Name: "idx_fs_pointlocation_geom", + Columns: []indexColumn{ + { + Name: "geom", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: false, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, }, PrimaryKey: &constraint{ Name: "fs_pointlocation_pkey", @@ -536,21 +562,23 @@ type fsPointlocationColumns struct { Scalarpriority column Sourcestatus column Updated column + Geom column } func (c fsPointlocationColumns) AsSlice() []column { return []column{ - c.OrganizationID, c.Accessdesc, c.Active, c.Comments, c.Creationdate, c.Creator, c.Description, c.Externalid, c.Editdate, c.Editor, c.Globalid, c.Habitat, c.Jurisdiction, c.Larvinspectinterval, c.Lastinspectactiontaken, c.Lastinspectactivity, c.Lastinspectavglarvae, c.Lastinspectavgpupae, c.Lastinspectbreeding, c.Lastinspectconditions, c.Lastinspectdate, c.Lastinspectfieldspecies, c.Lastinspectlstages, c.Lasttreatactivity, c.Lasttreatdate, c.Lasttreatproduct, c.Lasttreatqty, c.Lasttreatqtyunit, c.Locationnumber, c.Name, c.Nextactiondatescheduled, c.Objectid, c.Priority, c.Stype, c.Symbology, c.Usetype, c.Waterorigin, c.X, c.Y, c.Zone, c.Zone2, c.GeometryX, c.GeometryY, c.Assignedtech, c.DeactivateReason, c.Scalarpriority, c.Sourcestatus, c.Updated, + c.OrganizationID, c.Accessdesc, c.Active, c.Comments, c.Creationdate, c.Creator, c.Description, c.Externalid, c.Editdate, c.Editor, c.Globalid, c.Habitat, c.Jurisdiction, c.Larvinspectinterval, c.Lastinspectactiontaken, c.Lastinspectactivity, c.Lastinspectavglarvae, c.Lastinspectavgpupae, c.Lastinspectbreeding, c.Lastinspectconditions, c.Lastinspectdate, c.Lastinspectfieldspecies, c.Lastinspectlstages, c.Lasttreatactivity, c.Lasttreatdate, c.Lasttreatproduct, c.Lasttreatqty, c.Lasttreatqtyunit, c.Locationnumber, c.Name, c.Nextactiondatescheduled, c.Objectid, c.Priority, c.Stype, c.Symbology, c.Usetype, c.Waterorigin, c.X, c.Y, c.Zone, c.Zone2, c.GeometryX, c.GeometryY, c.Assignedtech, c.DeactivateReason, c.Scalarpriority, c.Sourcestatus, c.Updated, c.Geom, } } type fsPointlocationIndexes struct { - FSPointlocationPkey index + FSPointlocationPkey index + IdxFSPointlocationGeom index } func (i fsPointlocationIndexes) AsSlice() []index { return []index{ - i.FSPointlocationPkey, + i.FSPointlocationPkey, i.IdxFSPointlocationGeom, } } diff --git a/dbinfo/fs_traplocation.bob.go b/dbinfo/fs_traplocation.bob.go index 62dedc80..7fae1806 100644 --- a/dbinfo/fs_traplocation.bob.go +++ b/dbinfo/fs_traplocation.bob.go @@ -321,6 +321,15 @@ var FSTraplocations = Table[ Generated: false, AutoIncr: false, }, + Geom: column{ + Name: "geom", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: fsTraplocationIndexes{ FSTraplocationPkey: index{ @@ -340,6 +349,23 @@ var FSTraplocations = Table[ Where: "", Include: []string{}, }, + IdxFSTraplocationGeom: index{ + Type: "gist", + Name: "idx_fs_traplocation_geom", + Columns: []indexColumn{ + { + Name: "geom", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: false, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, }, PrimaryKey: &constraint{ Name: "fs_traplocation_pkey", @@ -396,21 +422,23 @@ type fsTraplocationColumns struct { H3R7 column H3R8 column Updated column + Geom column } func (c fsTraplocationColumns) AsSlice() []column { return []column{ - c.OrganizationID, c.Accessdesc, c.Active, c.Comments, c.Creationdate, c.Creator, c.Description, c.Externalid, c.Editdate, c.Editor, c.Gatewaysync, c.Globalid, c.Habitat, c.Locationnumber, c.Name, c.Nextactiondatescheduled, c.Objectid, c.Priority, c.Usetype, c.Zone, c.Zone2, c.CreatedDate, c.CreatedUser, c.GeometryX, c.GeometryY, c.LastEditedDate, c.LastEditedUser, c.Route, c.RouteOrder, c.SetDow, c.Vectorsurvsiteid, c.H3R7, c.H3R8, c.Updated, + c.OrganizationID, c.Accessdesc, c.Active, c.Comments, c.Creationdate, c.Creator, c.Description, c.Externalid, c.Editdate, c.Editor, c.Gatewaysync, c.Globalid, c.Habitat, c.Locationnumber, c.Name, c.Nextactiondatescheduled, c.Objectid, c.Priority, c.Usetype, c.Zone, c.Zone2, c.CreatedDate, c.CreatedUser, c.GeometryX, c.GeometryY, c.LastEditedDate, c.LastEditedUser, c.Route, c.RouteOrder, c.SetDow, c.Vectorsurvsiteid, c.H3R7, c.H3R8, c.Updated, c.Geom, } } type fsTraplocationIndexes struct { - FSTraplocationPkey index + FSTraplocationPkey index + IdxFSTraplocationGeom index } func (i fsTraplocationIndexes) AsSlice() []index { return []index{ - i.FSTraplocationPkey, + i.FSTraplocationPkey, i.IdxFSTraplocationGeom, } } diff --git a/dbinfo/fs_treatment.bob.go b/dbinfo/fs_treatment.bob.go index 06bd164c..c3a868f0 100644 --- a/dbinfo/fs_treatment.bob.go +++ b/dbinfo/fs_treatment.bob.go @@ -537,6 +537,15 @@ var FSTreatments = Table[ Generated: false, AutoIncr: false, }, + Geom: column{ + Name: "geom", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: fsTreatmentIndexes{ FSTreatmentPkey: index{ @@ -556,6 +565,23 @@ var FSTreatments = Table[ Where: "", Include: []string{}, }, + IdxFSTreatmentGeom: index{ + Type: "gist", + Name: "idx_fs_treatment_geom", + Columns: []indexColumn{ + { + Name: "geom", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: false, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, }, PrimaryKey: &constraint{ Name: "fs_treatment_pkey", @@ -636,21 +662,23 @@ type fsTreatmentColumns struct { GeometryY column TempSitecond column Updated column + Geom column } func (c fsTreatmentColumns) AsSlice() []column { return []column{ - c.OrganizationID, c.Activity, c.Areaunit, c.Avetemp, c.Barrierrouteid, c.Cbcount, c.Comments, c.Containercount, c.Creationdate, c.Creator, c.Enddatetime, c.Equiptype, c.Editdate, c.Editor, c.Fieldtech, c.Flowrate, c.Globalid, c.Habitat, c.InspID, c.Invloc, c.Linelocid, c.Locationname, c.Method, c.Objectid, c.Pointlocid, c.Polygonlocid, c.Product, c.Ptaid, c.Qty, c.Qtyunit, c.Raingauge, c.Recordstatus, c.Reviewed, c.Reviewedby, c.Revieweddate, c.Sdid, c.Sitecond, c.Srid, c.Startdatetime, c.Targetspecies, c.Tirecount, c.Treatacres, c.Treatarea, c.Treathectares, c.Treatmenthours, c.Treatmentlength, c.Treatmentlengthunits, c.Totalcostprodcut, c.Ulvrouteid, c.Warningoverride, c.Winddir, c.Windspeed, c.Zone, c.Zone2, c.GeometryX, c.GeometryY, c.TempSitecond, c.Updated, + c.OrganizationID, c.Activity, c.Areaunit, c.Avetemp, c.Barrierrouteid, c.Cbcount, c.Comments, c.Containercount, c.Creationdate, c.Creator, c.Enddatetime, c.Equiptype, c.Editdate, c.Editor, c.Fieldtech, c.Flowrate, c.Globalid, c.Habitat, c.InspID, c.Invloc, c.Linelocid, c.Locationname, c.Method, c.Objectid, c.Pointlocid, c.Polygonlocid, c.Product, c.Ptaid, c.Qty, c.Qtyunit, c.Raingauge, c.Recordstatus, c.Reviewed, c.Reviewedby, c.Revieweddate, c.Sdid, c.Sitecond, c.Srid, c.Startdatetime, c.Targetspecies, c.Tirecount, c.Treatacres, c.Treatarea, c.Treathectares, c.Treatmenthours, c.Treatmentlength, c.Treatmentlengthunits, c.Totalcostprodcut, c.Ulvrouteid, c.Warningoverride, c.Winddir, c.Windspeed, c.Zone, c.Zone2, c.GeometryX, c.GeometryY, c.TempSitecond, c.Updated, c.Geom, } } type fsTreatmentIndexes struct { - FSTreatmentPkey index + FSTreatmentPkey index + IdxFSTreatmentGeom index } func (i fsTreatmentIndexes) AsSlice() []index { return []index{ - i.FSTreatmentPkey, + i.FSTreatmentPkey, i.IdxFSTreatmentGeom, } } diff --git a/dbinfo/h3_aggregation.bob.go b/dbinfo/h3_aggregation.bob.go index 1aed4de0..a150291e 100644 --- a/dbinfo/h3_aggregation.bob.go +++ b/dbinfo/h3_aggregation.bob.go @@ -33,8 +33,8 @@ var H3Aggregations = Table[ Generated: false, AutoIncr: false, }, - Resolution: column{ - Name: "resolution", + Count: column{ + Name: "count_", DBType: "integer", Default: "", Comment: "", @@ -42,8 +42,26 @@ var H3Aggregations = Table[ Generated: false, AutoIncr: false, }, - Count: column{ - Name: "count_", + Geometry: column{ + Name: "geometry", + DBType: "geometry", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + OrganizationID: column{ + Name: "organization_id", + DBType: "integer", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Resolution: column{ + Name: "resolution", DBType: "integer", Default: "", Comment: "", @@ -60,15 +78,6 @@ var H3Aggregations = Table[ Generated: false, AutoIncr: false, }, - OrganizationID: column{ - Name: "organization_id", - DBType: "integer", - Default: "", - Comment: "", - Nullable: false, - Generated: false, - AutoIncr: false, - }, }, Indexes: h3AggregationIndexes{ H3AggregationPkey: index{ @@ -146,15 +155,16 @@ var H3Aggregations = Table[ type h3AggregationColumns struct { ID column Cell column - Resolution column Count column - Type column + Geometry column OrganizationID column + Resolution column + Type column } func (c h3AggregationColumns) AsSlice() []column { return []column{ - c.ID, c.Cell, c.Resolution, c.Count, c.Type, c.OrganizationID, + c.ID, c.Cell, c.Count, c.Geometry, c.OrganizationID, c.Resolution, c.Type, } } diff --git a/factory/bobfactory_main.bob.go b/factory/bobfactory_main.bob.go index 0e299623..d11e3e97 100644 --- a/factory/bobfactory_main.bob.go +++ b/factory/bobfactory_main.bob.go @@ -561,6 +561,7 @@ func (f *Factory) FromExistingFSMosquitoinspection(m *models.FSMosquitoinspectio o.Adminaction = func() null.Val[string] { return m.Adminaction } o.Ptaid = func() null.Val[string] { return m.Ptaid } o.Updated = func() time.Time { return m.Updated } + o.Geom = func() null.Val[string] { return m.Geom } ctx := context.Background() if m.R.Organization != nil { @@ -637,6 +638,7 @@ func (f *Factory) FromExistingFSPointlocation(m *models.FSPointlocation) *FSPoin o.Scalarpriority = func() null.Val[int64] { return m.Scalarpriority } o.Sourcestatus = func() null.Val[string] { return m.Sourcestatus } o.Updated = func() time.Time { return m.Updated } + o.Geom = func() null.Val[string] { return m.Geom } ctx := context.Background() if m.R.Organization != nil { @@ -1598,6 +1600,7 @@ func (f *Factory) FromExistingFSTraplocation(m *models.FSTraplocation) *FSTraplo o.H3R7 = func() null.Val[string] { return m.H3R7 } o.H3R8 = func() null.Val[string] { return m.H3R8 } o.Updated = func() time.Time { return m.Updated } + o.Geom = func() null.Val[string] { return m.Geom } ctx := context.Background() if m.R.Organization != nil { @@ -1684,6 +1687,7 @@ func (f *Factory) FromExistingFSTreatment(m *models.FSTreatment) *FSTreatmentTem o.GeometryY = func() null.Val[float64] { return m.GeometryY } o.TempSitecond = func() null.Val[string] { return m.TempSitecond } o.Updated = func() time.Time { return m.Updated } + o.Geom = func() null.Val[string] { return m.Geom } ctx := context.Background() if m.R.Organization != nil { @@ -1942,10 +1946,11 @@ func (f *Factory) FromExistingH3Aggregation(m *models.H3Aggregation) *H3Aggregat o.ID = func() int32 { return m.ID } o.Cell = func() string { return m.Cell } - o.Resolution = func() int32 { return m.Resolution } o.Count = func() int32 { return m.Count } - o.Type = func() enums.H3aggregationtype { return m.Type } + o.Geometry = func() null.Val[string] { return m.Geometry } o.OrganizationID = func() int32 { return m.OrganizationID } + o.Resolution = func() int32 { return m.Resolution } + o.Type = func() enums.H3aggregationtype { return m.Type } ctx := context.Background() if m.R.Organization != nil { diff --git a/factory/fs_mosquitoinspection.bob.go b/factory/fs_mosquitoinspection.bob.go index 9c9fd7f3..0e18a7c0 100644 --- a/factory/fs_mosquitoinspection.bob.go +++ b/factory/fs_mosquitoinspection.bob.go @@ -98,6 +98,7 @@ type FSMosquitoinspectionTemplate struct { Adminaction func() null.Val[string] Ptaid func() null.Val[string] Updated func() time.Time + Geom func() null.Val[string] r fsMosquitoinspectionR f *Factory @@ -380,6 +381,10 @@ func (o FSMosquitoinspectionTemplate) BuildSetter() *models.FSMosquitoinspection val := o.Updated() m.Updated = omit.From(val) } + if o.Geom != nil { + val := o.Geom() + m.Geom = omitnull.FromNull(val) + } return m } @@ -585,6 +590,9 @@ func (o FSMosquitoinspectionTemplate) Build() *models.FSMosquitoinspection { if o.Updated != nil { m.Updated = o.Updated() } + if o.Geom != nil { + m.Geom = o.Geom() + } o.setModelRels(m) @@ -797,6 +805,7 @@ func (m fsMosquitoinspectionMods) RandomizeAllColumns(f *faker.Faker) FSMosquito FSMosquitoinspectionMods.RandomAdminaction(f), FSMosquitoinspectionMods.RandomPtaid(f), FSMosquitoinspectionMods.RandomUpdated(f), + FSMosquitoinspectionMods.RandomGeom(f), } } @@ -3945,6 +3954,59 @@ func (m fsMosquitoinspectionMods) RandomUpdated(f *faker.Faker) FSMosquitoinspec }) } +// Set the model columns to this value +func (m fsMosquitoinspectionMods) Geom(val null.Val[string]) FSMosquitoinspectionMod { + return FSMosquitoinspectionModFunc(func(_ context.Context, o *FSMosquitoinspectionTemplate) { + o.Geom = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fsMosquitoinspectionMods) GeomFunc(f func() null.Val[string]) FSMosquitoinspectionMod { + return FSMosquitoinspectionModFunc(func(_ context.Context, o *FSMosquitoinspectionTemplate) { + o.Geom = f + }) +} + +// Clear any values for the column +func (m fsMosquitoinspectionMods) UnsetGeom() FSMosquitoinspectionMod { + return FSMosquitoinspectionModFunc(func(_ context.Context, o *FSMosquitoinspectionTemplate) { + 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 fsMosquitoinspectionMods) RandomGeom(f *faker.Faker) FSMosquitoinspectionMod { + return FSMosquitoinspectionModFunc(func(_ context.Context, o *FSMosquitoinspectionTemplate) { + 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 fsMosquitoinspectionMods) RandomGeomNotNull(f *faker.Faker) FSMosquitoinspectionMod { + return FSMosquitoinspectionModFunc(func(_ context.Context, o *FSMosquitoinspectionTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + func (m fsMosquitoinspectionMods) WithParentsCascading() FSMosquitoinspectionMod { return FSMosquitoinspectionModFunc(func(ctx context.Context, o *FSMosquitoinspectionTemplate) { if isDone, _ := fsMosquitoinspectionWithParentsCascadingCtx.Value(ctx); isDone { diff --git a/factory/fs_pointlocation.bob.go b/factory/fs_pointlocation.bob.go index 86112f6c..95fe753c 100644 --- a/factory/fs_pointlocation.bob.go +++ b/factory/fs_pointlocation.bob.go @@ -85,6 +85,7 @@ type FSPointlocationTemplate struct { Scalarpriority func() null.Val[int64] Sourcestatus func() null.Val[string] Updated func() time.Time + Geom func() null.Val[string] r fsPointlocationR f *Factory @@ -315,6 +316,10 @@ func (o FSPointlocationTemplate) BuildSetter() *models.FSPointlocationSetter { val := o.Updated() m.Updated = omit.From(val) } + if o.Geom != nil { + val := o.Geom() + m.Geom = omitnull.FromNull(val) + } return m } @@ -481,6 +486,9 @@ func (o FSPointlocationTemplate) Build() *models.FSPointlocation { if o.Updated != nil { m.Updated = o.Updated() } + if o.Geom != nil { + m.Geom = o.Geom() + } o.setModelRels(m) @@ -688,6 +696,7 @@ func (m fsPointlocationMods) RandomizeAllColumns(f *faker.Faker) FSPointlocation FSPointlocationMods.RandomScalarpriority(f), FSPointlocationMods.RandomSourcestatus(f), FSPointlocationMods.RandomUpdated(f), + FSPointlocationMods.RandomGeom(f), } } @@ -3103,6 +3112,59 @@ func (m fsPointlocationMods) RandomUpdated(f *faker.Faker) FSPointlocationMod { }) } +// Set the model columns to this value +func (m fsPointlocationMods) Geom(val null.Val[string]) FSPointlocationMod { + return FSPointlocationModFunc(func(_ context.Context, o *FSPointlocationTemplate) { + o.Geom = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fsPointlocationMods) GeomFunc(f func() null.Val[string]) FSPointlocationMod { + return FSPointlocationModFunc(func(_ context.Context, o *FSPointlocationTemplate) { + o.Geom = f + }) +} + +// Clear any values for the column +func (m fsPointlocationMods) UnsetGeom() FSPointlocationMod { + return FSPointlocationModFunc(func(_ context.Context, o *FSPointlocationTemplate) { + 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 fsPointlocationMods) RandomGeom(f *faker.Faker) FSPointlocationMod { + return FSPointlocationModFunc(func(_ context.Context, o *FSPointlocationTemplate) { + 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 fsPointlocationMods) RandomGeomNotNull(f *faker.Faker) FSPointlocationMod { + return FSPointlocationModFunc(func(_ context.Context, o *FSPointlocationTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + func (m fsPointlocationMods) WithParentsCascading() FSPointlocationMod { return FSPointlocationModFunc(func(ctx context.Context, o *FSPointlocationTemplate) { if isDone, _ := fsPointlocationWithParentsCascadingCtx.Value(ctx); isDone { diff --git a/factory/fs_traplocation.bob.go b/factory/fs_traplocation.bob.go index b8faef08..c8660984 100644 --- a/factory/fs_traplocation.bob.go +++ b/factory/fs_traplocation.bob.go @@ -71,6 +71,7 @@ type FSTraplocationTemplate struct { H3R7 func() null.Val[string] H3R8 func() null.Val[string] Updated func() time.Time + Geom func() null.Val[string] r fsTraplocationR f *Factory @@ -245,6 +246,10 @@ func (o FSTraplocationTemplate) BuildSetter() *models.FSTraplocationSetter { val := o.Updated() m.Updated = omit.From(val) } + if o.Geom != nil { + val := o.Geom() + m.Geom = omitnull.FromNull(val) + } return m } @@ -369,6 +374,9 @@ func (o FSTraplocationTemplate) Build() *models.FSTraplocation { if o.Updated != nil { m.Updated = o.Updated() } + if o.Geom != nil { + m.Geom = o.Geom() + } o.setModelRels(m) @@ -554,6 +562,7 @@ func (m fsTraplocationMods) RandomizeAllColumns(f *faker.Faker) FSTraplocationMo FSTraplocationMods.RandomH3R7(f), FSTraplocationMods.RandomH3R8(f), FSTraplocationMods.RandomUpdated(f), + FSTraplocationMods.RandomGeom(f), } } @@ -2271,6 +2280,59 @@ func (m fsTraplocationMods) RandomUpdated(f *faker.Faker) FSTraplocationMod { }) } +// Set the model columns to this value +func (m fsTraplocationMods) Geom(val null.Val[string]) FSTraplocationMod { + return FSTraplocationModFunc(func(_ context.Context, o *FSTraplocationTemplate) { + o.Geom = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fsTraplocationMods) GeomFunc(f func() null.Val[string]) FSTraplocationMod { + return FSTraplocationModFunc(func(_ context.Context, o *FSTraplocationTemplate) { + o.Geom = f + }) +} + +// Clear any values for the column +func (m fsTraplocationMods) UnsetGeom() FSTraplocationMod { + return FSTraplocationModFunc(func(_ context.Context, o *FSTraplocationTemplate) { + 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 fsTraplocationMods) RandomGeom(f *faker.Faker) FSTraplocationMod { + return FSTraplocationModFunc(func(_ context.Context, o *FSTraplocationTemplate) { + 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 fsTraplocationMods) RandomGeomNotNull(f *faker.Faker) FSTraplocationMod { + return FSTraplocationModFunc(func(_ context.Context, o *FSTraplocationTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + func (m fsTraplocationMods) WithParentsCascading() FSTraplocationMod { return FSTraplocationModFunc(func(ctx context.Context, o *FSTraplocationTemplate) { if isDone, _ := fsTraplocationWithParentsCascadingCtx.Value(ctx); isDone { diff --git a/factory/fs_treatment.bob.go b/factory/fs_treatment.bob.go index 84e060d1..d73fdfce 100644 --- a/factory/fs_treatment.bob.go +++ b/factory/fs_treatment.bob.go @@ -95,6 +95,7 @@ type FSTreatmentTemplate struct { GeometryY func() null.Val[float64] TempSitecond func() null.Val[string] Updated func() time.Time + Geom func() null.Val[string] r fsTreatmentR f *Factory @@ -365,6 +366,10 @@ func (o FSTreatmentTemplate) BuildSetter() *models.FSTreatmentSetter { val := o.Updated() m.Updated = omit.From(val) } + if o.Geom != nil { + val := o.Geom() + m.Geom = omitnull.FromNull(val) + } return m } @@ -561,6 +566,9 @@ func (o FSTreatmentTemplate) Build() *models.FSTreatment { if o.Updated != nil { m.Updated = o.Updated() } + if o.Geom != nil { + m.Geom = o.Geom() + } o.setModelRels(m) @@ -770,6 +778,7 @@ func (m fsTreatmentMods) RandomizeAllColumns(f *faker.Faker) FSTreatmentMod { FSTreatmentMods.RandomGeometryY(f), FSTreatmentMods.RandomTempSitecond(f), FSTreatmentMods.RandomUpdated(f), + FSTreatmentMods.RandomGeom(f), } } @@ -3759,6 +3768,59 @@ func (m fsTreatmentMods) RandomUpdated(f *faker.Faker) FSTreatmentMod { }) } +// Set the model columns to this value +func (m fsTreatmentMods) Geom(val null.Val[string]) FSTreatmentMod { + return FSTreatmentModFunc(func(_ context.Context, o *FSTreatmentTemplate) { + o.Geom = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m fsTreatmentMods) GeomFunc(f func() null.Val[string]) FSTreatmentMod { + return FSTreatmentModFunc(func(_ context.Context, o *FSTreatmentTemplate) { + o.Geom = f + }) +} + +// Clear any values for the column +func (m fsTreatmentMods) UnsetGeom() FSTreatmentMod { + return FSTreatmentModFunc(func(_ context.Context, o *FSTreatmentTemplate) { + 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 fsTreatmentMods) RandomGeom(f *faker.Faker) FSTreatmentMod { + return FSTreatmentModFunc(func(_ context.Context, o *FSTreatmentTemplate) { + 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 fsTreatmentMods) RandomGeomNotNull(f *faker.Faker) FSTreatmentMod { + return FSTreatmentModFunc(func(_ context.Context, o *FSTreatmentTemplate) { + o.Geom = func() null.Val[string] { + if f == nil { + f = &defaultFaker + } + + val := random_string(f) + return null.From(val) + } + }) +} + func (m fsTreatmentMods) WithParentsCascading() FSTreatmentMod { return FSTreatmentModFunc(func(ctx context.Context, o *FSTreatmentTemplate) { if isDone, _ := fsTreatmentWithParentsCascadingCtx.Value(ctx); isDone { diff --git a/factory/h3_aggregation.bob.go b/factory/h3_aggregation.bob.go index 41b0c677..c3a29299 100644 --- a/factory/h3_aggregation.bob.go +++ b/factory/h3_aggregation.bob.go @@ -9,7 +9,9 @@ import ( enums "github.com/Gleipnir-Technology/nidus-sync/enums" models "github.com/Gleipnir-Technology/nidus-sync/models" + "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" "github.com/jaswdr/faker/v2" "github.com/stephenafamo/bob" ) @@ -37,10 +39,11 @@ func (mods H3AggregationModSlice) Apply(ctx context.Context, n *H3AggregationTem type H3AggregationTemplate struct { ID func() int32 Cell func() string - Resolution func() int32 Count func() int32 - Type func() enums.H3aggregationtype + Geometry func() null.Val[string] OrganizationID func() int32 + Resolution func() int32 + Type func() enums.H3aggregationtype r h3AggregationR f *Factory @@ -87,22 +90,26 @@ func (o H3AggregationTemplate) BuildSetter() *models.H3AggregationSetter { val := o.Cell() m.Cell = omit.From(val) } - if o.Resolution != nil { - val := o.Resolution() - m.Resolution = omit.From(val) - } if o.Count != nil { val := o.Count() m.Count = omit.From(val) } - if o.Type != nil { - val := o.Type() - m.Type = omit.From(val) + if o.Geometry != nil { + val := o.Geometry() + m.Geometry = omitnull.FromNull(val) } if o.OrganizationID != nil { val := o.OrganizationID() m.OrganizationID = omit.From(val) } + if o.Resolution != nil { + val := o.Resolution() + m.Resolution = omit.From(val) + } + if o.Type != nil { + val := o.Type() + m.Type = omit.From(val) + } return m } @@ -131,18 +138,21 @@ func (o H3AggregationTemplate) Build() *models.H3Aggregation { if o.Cell != nil { m.Cell = o.Cell() } - if o.Resolution != nil { - m.Resolution = o.Resolution() - } if o.Count != nil { m.Count = o.Count() } - if o.Type != nil { - m.Type = o.Type() + if o.Geometry != nil { + m.Geometry = o.Geometry() } if o.OrganizationID != nil { m.OrganizationID = o.OrganizationID() } + if o.Resolution != nil { + m.Resolution = o.Resolution() + } + if o.Type != nil { + m.Type = o.Type() + } o.setModelRels(m) @@ -167,22 +177,22 @@ func ensureCreatableH3Aggregation(m *models.H3AggregationSetter) { val := random_string(nil) m.Cell = omit.From(val) } - if !(m.Resolution.IsValue()) { - val := random_int32(nil) - m.Resolution = omit.From(val) - } if !(m.Count.IsValue()) { val := random_int32(nil) m.Count = omit.From(val) } - if !(m.Type.IsValue()) { - val := random_enums_H3aggregationtype(nil) - m.Type = omit.From(val) - } if !(m.OrganizationID.IsValue()) { val := random_int32(nil) m.OrganizationID = omit.From(val) } + if !(m.Resolution.IsValue()) { + val := random_int32(nil) + m.Resolution = omit.From(val) + } + if !(m.Type.IsValue()) { + val := random_enums_H3aggregationtype(nil) + m.Type = omit.From(val) + } } // insertOptRels creates and inserts any optional the relationships on *models.H3Aggregation @@ -304,10 +314,11 @@ func (m h3AggregationMods) RandomizeAllColumns(f *faker.Faker) H3AggregationMod return H3AggregationModSlice{ H3AggregationMods.RandomID(f), H3AggregationMods.RandomCell(f), - H3AggregationMods.RandomResolution(f), H3AggregationMods.RandomCount(f), - H3AggregationMods.RandomType(f), + H3AggregationMods.RandomGeometry(f), H3AggregationMods.RandomOrganizationID(f), + H3AggregationMods.RandomResolution(f), + H3AggregationMods.RandomType(f), } } @@ -373,37 +384,6 @@ func (m h3AggregationMods) RandomCell(f *faker.Faker) H3AggregationMod { }) } -// Set the model columns to this value -func (m h3AggregationMods) Resolution(val int32) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.Resolution = func() int32 { return val } - }) -} - -// Set the Column from the function -func (m h3AggregationMods) ResolutionFunc(f func() int32) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.Resolution = f - }) -} - -// Clear any values for the column -func (m h3AggregationMods) UnsetResolution() H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.Resolution = nil - }) -} - -// Generates a random value for the column using the given faker -// if faker is nil, a default faker is used -func (m h3AggregationMods) RandomResolution(f *faker.Faker) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.Resolution = func() int32 { - return random_int32(f) - } - }) -} - // Set the model columns to this value func (m h3AggregationMods) Count(val int32) H3AggregationMod { return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { @@ -435,6 +415,121 @@ func (m h3AggregationMods) RandomCount(f *faker.Faker) H3AggregationMod { }) } +// Set the model columns to this value +func (m h3AggregationMods) Geometry(val null.Val[string]) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Geometry = func() null.Val[string] { return val } + }) +} + +// Set the Column from the function +func (m h3AggregationMods) GeometryFunc(f func() null.Val[string]) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Geometry = f + }) +} + +// Clear any values for the column +func (m h3AggregationMods) UnsetGeometry() H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Geometry = 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 h3AggregationMods) RandomGeometry(f *faker.Faker) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Geometry = 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 h3AggregationMods) RandomGeometryNotNull(f *faker.Faker) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Geometry = 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 h3AggregationMods) OrganizationID(val int32) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.OrganizationID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m h3AggregationMods) OrganizationIDFunc(f func() int32) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.OrganizationID = f + }) +} + +// Clear any values for the column +func (m h3AggregationMods) UnsetOrganizationID() H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + 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 h3AggregationMods) RandomOrganizationID(f *faker.Faker) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.OrganizationID = func() int32 { + return random_int32(f) + } + }) +} + +// Set the model columns to this value +func (m h3AggregationMods) Resolution(val int32) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Resolution = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m h3AggregationMods) ResolutionFunc(f func() int32) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Resolution = f + }) +} + +// Clear any values for the column +func (m h3AggregationMods) UnsetResolution() H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Resolution = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m h3AggregationMods) RandomResolution(f *faker.Faker) H3AggregationMod { + return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { + o.Resolution = func() int32 { + return random_int32(f) + } + }) +} + // Set the model columns to this value func (m h3AggregationMods) Type(val enums.H3aggregationtype) H3AggregationMod { return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { @@ -466,37 +561,6 @@ func (m h3AggregationMods) RandomType(f *faker.Faker) H3AggregationMod { }) } -// Set the model columns to this value -func (m h3AggregationMods) OrganizationID(val int32) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.OrganizationID = func() int32 { return val } - }) -} - -// Set the Column from the function -func (m h3AggregationMods) OrganizationIDFunc(f func() int32) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.OrganizationID = f - }) -} - -// Clear any values for the column -func (m h3AggregationMods) UnsetOrganizationID() H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - 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 h3AggregationMods) RandomOrganizationID(f *faker.Faker) H3AggregationMod { - return H3AggregationModFunc(func(_ context.Context, o *H3AggregationTemplate) { - o.OrganizationID = func() int32 { - return random_int32(f) - } - }) -} - func (m h3AggregationMods) WithParentsCascading() H3AggregationMod { return H3AggregationModFunc(func(ctx context.Context, o *H3AggregationTemplate) { if isDone, _ := h3AggregationWithParentsCascadingCtx.Value(ctx); isDone { diff --git a/fieldseeker.go b/fieldseeker.go new file mode 100644 index 00000000..459ad588 --- /dev/null +++ b/fieldseeker.go @@ -0,0 +1,15 @@ +package main + +import ( + "time" + + "github.com/aarondl/opt/null" +) + +func fsTimestampToTime(t null.Val[int64]) *time.Time { + if t.IsNull() { + return nil + } + result := time.UnixMilli(t.MustGet()) + return &result +} diff --git a/go.mod b/go.mod index 1a59614b..448286a1 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/lib/pq v1.10.9 github.com/pressly/goose/v3 v3.26.0 github.com/rs/zerolog v1.34.0 + github.com/shopspring/decimal v1.4.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stephenafamo/bob v0.41.1 github.com/stephenafamo/scan v0.7.0 @@ -49,7 +50,6 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/rtree v1.3.1 // indirect github.com/tidwall/sjson v1.2.4 // indirect - github.com/uber/h3-go/v3 v3.7.1 // indirect github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect github.com/x448/float16 v0.8.4 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index 5eab6415..4b12210e 100644 --- a/go.sum +++ b/go.sum @@ -153,6 +153,8 @@ github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= @@ -202,8 +204,6 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/uber/h3-go/v3 v3.7.1 h1:qGAnkRKXHeuaGuLDktcouROiNDE1PgZTgiZGMBwVnSc= -github.com/uber/h3-go/v3 v3.7.1/go.mod h1:XS+EMzW0EmjL/aioQsvLIYJRtC7/lodai5l8SNmlYIs= github.com/uber/h3-go/v4 v4.3.0 h1:5y5je8gu6+1pGzGo8soiudmgE3WJzfJRWdy0yhc3+HY= github.com/uber/h3-go/v4 v4.3.0/go.mod h1:EyZ/EWguHlheIBcshTAMmQPYcaGKVvJ4qlzEHzC0BkU= github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo= diff --git a/html.go b/html.go index 6dea3ce3..ff420996 100644 --- a/html.go +++ b/html.go @@ -16,9 +16,11 @@ import ( "time" "github.com/Gleipnir-Technology/nidus-sync/models" + "github.com/Gleipnir-Technology/nidus-sync/sql" "github.com/aarondl/opt/null" //"github.com/riverqueue/river/rivershared/util/slogutil" //"github.com/rs/zerolog/log" + "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/psql" "github.com/stephenafamo/bob/dialect/psql/sm" "github.com/uber/h3-go/v4" @@ -73,10 +75,10 @@ type BuiltTemplate struct { } type MapMarker struct { - LatLng LatLng + LatLng h3.LatLng } type ComponentMap struct { - Center LatLng + Center h3.LatLng GeoJSON interface{} MapboxToken string Markers []MapMarker @@ -124,13 +126,10 @@ type ContentSource struct { Inspections []Inspection MapData ComponentMap Source *BreedingSourceDetail + Traps []TrapNearby Treatments []Treatment User User } -type LatLng struct { - Lat float64 - Lng float64 -} type Inspection struct { Action string Date time.Time @@ -266,7 +265,7 @@ func htmlCell(ctx context.Context, w http.ResponseWriter, user *models.User, c i CellBoundary: boundary, Inspections: inspections, MapData: ComponentMap{ - Center: LatLng{ + Center: h3.LatLng{ Lat: center.Lat, Lng: center.Lng, }, @@ -501,6 +500,12 @@ func htmlSource(w http.ResponseWriter, r *http.Request, user *models.User, id st respondError(w, "Failed to get inspections", err, http.StatusInternalServerError) return } + traps, err := trapsBySource(r.Context(), org, id) + if err != nil { + respondError(w, "Failed to get traps", err, http.StatusInternalServerError) + return + } + treatments, err := treatmentsBySource(r.Context(), org, id) if err != nil { respondError(w, "Failed to get treatments", err, http.StatusInternalServerError) @@ -509,23 +514,18 @@ func htmlSource(w http.ResponseWriter, r *http.Request, user *models.User, id st data := ContentSource{ Inspections: inspections, MapData: ComponentMap{ - Center: LatLng{ - Lat: s.GeometryY, - Lng: s.GeometryX, - }, + Center: s.LatLng, //GeoJSON: MapboxToken: MapboxToken, Markers: []MapMarker{ MapMarker{ - LatLng: LatLng{ - Lat: s.GeometryY, - Lng: s.GeometryX, - }, + LatLng: s.LatLng, }, }, Zoom: 13, }, Source: s, + Traps: traps, Treatments: treatments, User: userContent, } @@ -670,6 +670,40 @@ func timeSince(t *time.Time) string { } } +func trapsBySource(ctx context.Context, org *models.Organization, sourceID string) ([]TrapNearby, error) { + locations, err := sql.TrapLocationBySourceID(org.ID, sourceID).All(ctx, PGInstance.BobDB) + if err != nil { + return nil, fmt.Errorf("Failed to query rows: %w", err) + } + + location_ids := make([]string, 0) + var args []bob.Expression + for _, location := range locations { + location_ids = append(location_ids, location.TrapLocationGlobalid) + args = append(args, psql.Arg(location.TrapLocationGlobalid)) + } + trap_data, err := org.FSTrapdata( + sm.Where( + models.FSTrapdata.Columns.LocID.In(args...), + ), + sm.OrderBy("enddatetime"), + ).All(ctx, PGInstance.BobDB) + if err != nil { + return nil, fmt.Errorf("Failed to query trap data: %w", err) + } + + counts, err := sql.TrapCountByLocationID(org.ID, location_ids).All(ctx, PGInstance.BobDB) + if err != nil { + return nil, fmt.Errorf("Failed to query trap counts: %w", err) + } + + traps, err := toTemplateTraps(locations, trap_data, counts) + if err != nil { + return nil, fmt.Errorf("Failed to convert trap data: %w", err) + } + return traps, nil +} + func renderOrError(w http.ResponseWriter, template BuiltTemplate, context interface{}) { buf := &bytes.Buffer{} err := template.ExecuteTemplate(buf, context) diff --git a/migrations/00015_fs_geometry.sql b/migrations/00015_fs_geometry.sql index 383fb959..cdceeeee 100644 --- a/migrations/00015_fs_geometry.sql +++ b/migrations/00015_fs_geometry.sql @@ -1,14 +1,31 @@ -- +goose Up +ALTER TABLE fs_mosquitoinspection ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API +UPDATE fs_mosquitoinspection SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); +CREATE INDEX idx_fs_mosquitoinspection_geom ON fs_mosquitoinspection USING GIST(geom); + ALTER TABLE fs_pointlocation ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API UPDATE fs_pointlocation SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); +CREATE INDEX idx_fs_pointlocation_geom ON fs_pointlocation USING GIST(geom); + + +--ALTER TABLE fs_trapdata ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API +--UPDATE fs_trapdata SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); + +ALTER TABLE fs_traplocation ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API +UPDATE fs_traplocation SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); +CREATE INDEX idx_fs_traplocation_geom ON fs_traplocation USING GIST(geom); ALTER TABLE fs_treatment ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API UPDATE fs_treatment SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); - -ALTER TABLE fs_mosquitoinspection ADD COLUMN geom geometry(Point, 3857); -- as specified by the ArcGIS API -UPDATE fs_mosquitoinspection SET geom = ST_SetSRID(ST_MakePoint(geometry_x, geometry_y), 3857); +CREATE INDEX idx_fs_treatment_geom ON fs_treatment USING GIST(geom); -- +goose Down -ALTER TABLE fs_pointlocation DROP COLUMN geom; -ALTER TABLE fs_treatment DROP COLUMN geom; +DROP INDEX idx_fs_mosquitoinspection_geom; ALTER TABLE fs_mosquitoinspection DROP COLUMN geom; +DROP INDEX idx_fs_pointlocation_geom; +ALTER TABLE fs_pointlocation DROP COLUMN geom; +--ALTER TABLE fs_trapdata DROP COLUMN geom; +DROP INDEX idx_fs_traplocation_geom; +ALTER TABLE fs_traplocation DROP COLUMN geom; +DROP INDEX idx_fs_treatment_geom; +ALTER TABLE fs_treatment DROP COLUMN geom; diff --git a/model_conversion.go b/model_conversion.go index a74e2e7c..74b8501b 100644 --- a/model_conversion.go +++ b/model_conversion.go @@ -1,9 +1,14 @@ package main import ( - "github.com/Gleipnir-Technology/nidus-sync/models" - "github.com/aarondl/opt/null" + "errors" + "fmt" "time" + + "github.com/Gleipnir-Technology/nidus-sync/models" + "github.com/Gleipnir-Technology/nidus-sync/sql" + "github.com/aarondl/opt/null" + "github.com/uber/h3-go/v4" ) type BreedingSourceDetail struct { @@ -31,14 +36,11 @@ type BreedingSourceDetail struct { Symbology string `json:"symbology"` // Geographical Data - X float64 `json:"x"` - Y float64 `json:"y"` - GeometryX float64 `json:"geometryX"` - GeometryY float64 `json:"geometryY"` - Zone string `json:"zone"` - Zone2 string `json:"zone2"` - Jurisdiction string `json:"jurisdiction"` - AccessDescription string `json:"accessDescription"` + LatLng h3.LatLng `json:"latlng"` + Zone string `json:"zone"` + Zone2 string `json:"zone2"` + Jurisdiction string `json:"jurisdiction"` + AccessDescription string `json:"accessDescription"` // Inspection Data LarvaeInspectInterval int16 `json:"larvaeInspectInterval"` @@ -72,6 +74,203 @@ type BreedingSourceDetail struct { Comments string `json:"comments"` } +type TrapNearby struct { + Counts []*TrapCount + Distance string + ID string +} + +type TrapCount struct { + Ended time.Time + Females int + ID string + Males int + Total int +} + +type TrapData struct { + // Basic Identifiers + OrganizationID int32 `json:"organizationId"` + ObjectID int32 `json:"objectId"` + GlobalID string `json:"globalId"` + LocationName string `json:"locationName"` + LocationID string `json:"locationId"` + SRID string `json:"srid"` + Field int64 `json:"field"` + + // Trap Information + TrapType string `json:"trapType"` + TrapCondition string `json:"trapCondition"` + TrapActivityType string `json:"trapActivityType"` + TrapNights int16 `json:"trapNights"` + Lure string `json:"lureType"` + + // Personnel + FieldTechnician string `json:"fieldTechnician"` + IdentifiedByTechnician string `json:"identifiedByTechnician"` + SortedByTechnician string `json:"sortedByTechnician"` + + // Timing + StartDateTime time.Time `json:"startDateTime"` + EndDateTime time.Time `json:"endDateTime"` + + // Environmental Conditions + AverageTemperature float64 `json:"averageTemperature"` + Rainfall float64 `json:"rainfall"` + WindDirection string `json:"windDirection"` + WindSpeed float64 `json:"windSpeed"` + SiteCondition string `json:"siteCondition"` + + // Status and Processing + Processed bool `json:"processed"` + RecordStatus int16 `json:"recordStatus"` + Reviewed bool `json:"reviewed"` + ReviewedBy string `json:"reviewedBy"` + ReviewedDate time.Time `json:"reviewedDate"` + GatewaySynced bool `json:"gatewaySynced"` + LR bool `json:"laboratoryReported"` + Voltage float64 `json:"voltage"` + + // Location Data + GeometryX float64 `json:"geometryX"` + GeometryY float64 `json:"geometryY"` + Zone string `json:"zone"` + Zone2 string `json:"zone2"` + + // Vector Survey IDs + VectorSurveyTrapDataID string `json:"vectorSurveyTrapDataId"` + VectorSurveyTrapLocationID string `json:"vectorSurveyTrapLocationId"` + + // Metadata + Created time.Time `json:"created"` + Creator string `json:"creator"` + CreatedByUser string `json:"createdByUser"` + CreatedDateAlt time.Time `json:"createdDateAlt"` + Edited time.Time `json:"edited"` + Editor string `json:"editor"` + LastEditedDate time.Time `json:"lastEditedDate"` + LastEditedUser string `json:"lastEditedUser"` + Updated time.Time `json:"updated"` + Comments string `json:"comments"` +} + +func toTemplateTraps(locations []sql.TrapLocationBySourceIDRow, trap_data models.FSTrapdatumSlice, counts []sql.TrapCountByLocationIDRow) ([]TrapNearby, error) { + results := make([]TrapNearby, 0) + count_by_trap_data_id := make(map[string]*sql.TrapCountByLocationIDRow) + for _, c := range counts { + count_by_trap_data_id[c.TrapdataGlobalid] = &c + } + counts_by_location_id := make(map[string][]*TrapCount) + for _, td := range trap_data { + c, ok := count_by_trap_data_id[td.Globalid] + if !ok { + return results, errors.New(fmt.Sprintf("Failed to find trap count for %s", td.Globalid)) + } + if td.LocID.IsNull() { + return results, errors.New("Got a trap data with no location ID") + } + loc_id := td.LocID.MustGet() + count := &TrapCount{ + Ended: fsToTime(td.Enddatetime), + Females: int(c.TotalFemales.IntPart()), + ID: td.Globalid, + Males: int(c.TotalMales), + Total: int(c.Total.IntPart()), + } + counts, ok := counts_by_location_id[loc_id] + if !ok { + counts = []*TrapCount{count} + } else { + counts = append(counts, count) + } + counts_by_location_id[loc_id] = counts + } + for _, location := range locations { + counts, ok := counts_by_location_id[location.TrapLocationGlobalid] + if !ok { + return results, errors.New(fmt.Sprintf("Failed to find counts for %s", location.TrapLocationGlobalid)) + } + trap := TrapNearby{ + Counts: counts, + Distance: location.Distance, + ID: location.TrapLocationGlobalid, + } + results = append(results, trap) + } + return results, nil +} + +func toTemplateTrapData(trap_data models.FSTrapdatumSlice) ([]TrapData, error) { + var results []TrapData + for _, r := range trap_data { + results = append(results, TrapData{ + // Basic Identifiers + OrganizationID: r.OrganizationID, + ObjectID: r.Objectid, + GlobalID: r.Globalid, + LocationName: r.Locationname.GetOr(""), + LocationID: r.LocID.GetOr(""), + SRID: r.Srid.GetOr(""), + Field: r.Field.GetOr(0), + + // Trap Information + TrapType: r.Traptype.GetOr(""), + TrapCondition: r.Trapcondition.GetOr(""), + TrapActivityType: r.Trapactivitytype.GetOr(""), + TrapNights: r.Trapnights.GetOr(0), + Lure: r.Lure.GetOr(""), + + // Personnel + FieldTechnician: r.Fieldtech.GetOr(""), + IdentifiedByTechnician: r.Idbytech.GetOr(""), + SortedByTechnician: r.Sortbytech.GetOr(""), + + // Timing + StartDateTime: fsToTime(r.Startdatetime), + EndDateTime: fsToTime(r.Enddatetime), + + // Environmental Conditions + AverageTemperature: r.Avetemp.GetOr(0), + Rainfall: r.Raingauge.GetOr(0), + WindDirection: r.Winddir.GetOr(""), + WindSpeed: r.Windspeed.GetOr(0), + SiteCondition: r.Sitecond.GetOr(""), + + // Status and Processing + Processed: fsIntToBool(r.Processed), + RecordStatus: r.Recordstatus.GetOr(0), + Reviewed: fsIntToBool(r.Reviewed), + ReviewedBy: r.Reviewedby.GetOr(""), + ReviewedDate: fsToTime(r.Revieweddate), + GatewaySynced: fsIntToBool(r.Gatewaysync), + LR: fsIntToBool(r.LR), + Voltage: r.Voltage.GetOr(0), + + // Location Data + GeometryX: r.GeometryX.GetOr(0), + GeometryY: r.GeometryY.GetOr(0), + Zone: r.Zone.GetOr(""), + Zone2: r.Zone2.GetOr(""), + + // Vector Survey IDs + VectorSurveyTrapDataID: r.Vectorsurvtrapdataid.GetOr(""), + VectorSurveyTrapLocationID: r.Vectorsurvtraplocationid.GetOr(""), + + // Metadata + Created: fsToTime(r.Creationdate), + Creator: r.Creator.GetOr(""), + CreatedByUser: r.CreatedUser.GetOr(""), + CreatedDateAlt: fsToTime(r.CreatedDate), + Edited: fsToTime(r.Editdate), + Editor: r.Editor.GetOr(""), + LastEditedDate: fsToTime(r.LastEditedDate), + LastEditedUser: r.LastEditedUser.GetOr(""), + Updated: r.Updated, + Comments: r.Comments.GetOr(""), + }) + } + return results, nil +} func toTemplateTreatment(rows models.FSTreatmentSlice) ([]Treatment, error) { var results []Treatment for _, r := range rows { @@ -99,27 +298,27 @@ func toTemplateInspection(rows models.FSMosquitoinspectionSlice) ([]Inspection, return results, nil } +// Helper function to convert unix timestamp to time.Time +func fsToTime(val null.Val[int64]) time.Time { + v, ok := val.Get() + if !ok { + return time.UnixMilli(0) + } + t := time.UnixMilli(v) + return t +} + +// Helper function to convert int16 to bool +func fsIntToBool(val null.Val[int16]) bool { + if !val.IsValue() { + return false + } + b := val.MustGet() != 0 + return b +} + // toTemplateBreedingSource transforms the DB model into the display model func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDetail { - // Helper function to convert unix timestamp to time.Time - toTime := func(val null.Val[int64]) time.Time { - v, ok := val.Get() - if !ok { - return time.UnixMilli(0) - } - t := time.UnixMilli(v) - return t - } - - // Helper function to convert int16 to bool - toBool := func(val null.Val[int16]) bool { - if !val.IsValue() { - return false - } - b := val.MustGet() != 0 - return b - } - return &BreedingSourceDetail{ // Basic Information OrganizationID: source.OrganizationID, @@ -131,7 +330,7 @@ func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDet ExternalID: source.Externalid.GetOr(""), // Status Information - Active: toBool(source.Active), + Active: fsIntToBool(source.Active), DeactivateReason: source.DeactivateReason.GetOr(""), SourceStatus: source.Sourcestatus.GetOr(""), Priority: source.Priority.GetOr(""), @@ -145,10 +344,10 @@ func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDet Symbology: source.Symbology.GetOr(""), // Geographical Data - X: source.X.GetOr(0), - Y: source.Y.GetOr(0), - GeometryX: source.GeometryX, - GeometryY: source.GeometryY, + LatLng: h3.LatLng{ + Lat: source.GeometryY, + Lng: source.GeometryX, + }, Zone: source.Zone.GetOr(""), Zone2: source.Zone2.GetOr(""), Jurisdiction: source.Jurisdiction.GetOr(""), @@ -156,7 +355,7 @@ func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDet // Inspection Data LarvaeInspectInterval: source.Larvinspectinterval.GetOr(0), - LastInspectionDate: toTime(source.Lastinspectdate), + LastInspectionDate: fsToTime(source.Lastinspectdate), LastInspectionActivity: source.Lastinspectactivity.GetOr(""), LastInspectionActionTaken: source.Lastinspectactiontaken.GetOr(""), LastInspectionAverageLarvae: source.Lastinspectavglarvae.GetOr(0), @@ -167,7 +366,7 @@ func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDet LastInspectionLifeStages: source.Lastinspectlstages.GetOr(""), // Treatment Data - LastTreatmentDate: toTime(source.Lasttreatdate), + LastTreatmentDate: fsToTime(source.Lasttreatdate), LastTreatmentActivity: source.Lasttreatactivity.GetOr(""), LastTreatmentProduct: source.Lasttreatproduct.GetOr(""), LastTreatmentQuantity: source.Lasttreatqty.GetOr(0), @@ -175,12 +374,12 @@ func toTemplateBreedingSource(source *models.FSPointlocation) *BreedingSourceDet // Assignment & Schedule AssignedTechnician: source.Assignedtech.GetOr(""), - NextActionScheduledDate: toTime(source.Nextactiondatescheduled), + NextActionScheduledDate: fsToTime(source.Nextactiondatescheduled), // Metadata - Created: toTime(source.Creationdate), + Created: fsToTime(source.Creationdate), Creator: source.Creator.GetOr(""), - EditedAt: toTime(source.Editdate), + EditedAt: fsToTime(source.Editdate), Editor: source.Editor.GetOr(""), Updated: source.Updated, Comments: source.Comments.GetOr(""), diff --git a/models/fs_mosquitoinspection.bob.go b/models/fs_mosquitoinspection.bob.go index 3676a691..566745de 100644 --- a/models/fs_mosquitoinspection.bob.go +++ b/models/fs_mosquitoinspection.bob.go @@ -87,6 +87,7 @@ type FSMosquitoinspection struct { Adminaction null.Val[string] `db:"adminaction" ` Ptaid null.Val[string] `db:"ptaid" ` Updated time.Time `db:"updated" ` + Geom null.Val[string] `db:"geom" ` R fsMosquitoinspectionR `db:"-" ` } @@ -109,7 +110,7 @@ type fsMosquitoinspectionR struct { func buildFSMosquitoinspectionColumns(alias string) fsMosquitoinspectionColumns { return fsMosquitoinspectionColumns{ ColumnsExpr: expr.NewColumnsExpr( - "organization_id", "actiontaken", "activity", "adultact", "avetemp", "avglarvae", "avgpupae", "breeding", "cbcount", "comments", "containercount", "creationdate", "creator", "domstage", "eggs", "enddatetime", "editdate", "editor", "fieldspecies", "fieldtech", "globalid", "jurisdiction", "larvaepresent", "linelocid", "locationname", "lstages", "numdips", "objectid", "personalcontact", "pointlocid", "polygonlocid", "posdips", "positivecontainercount", "pupaepresent", "raingauge", "recordstatus", "reviewed", "reviewedby", "revieweddate", "sdid", "sitecond", "srid", "startdatetime", "tirecount", "totlarvae", "totpupae", "visualmonitoring", "vmcomments", "winddir", "windspeed", "zone", "zone2", "created_date", "created_user", "geometry_x", "geometry_y", "last_edited_date", "last_edited_user", "adminaction", "ptaid", "updated", + "organization_id", "actiontaken", "activity", "adultact", "avetemp", "avglarvae", "avgpupae", "breeding", "cbcount", "comments", "containercount", "creationdate", "creator", "domstage", "eggs", "enddatetime", "editdate", "editor", "fieldspecies", "fieldtech", "globalid", "jurisdiction", "larvaepresent", "linelocid", "locationname", "lstages", "numdips", "objectid", "personalcontact", "pointlocid", "polygonlocid", "posdips", "positivecontainercount", "pupaepresent", "raingauge", "recordstatus", "reviewed", "reviewedby", "revieweddate", "sdid", "sitecond", "srid", "startdatetime", "tirecount", "totlarvae", "totpupae", "visualmonitoring", "vmcomments", "winddir", "windspeed", "zone", "zone2", "created_date", "created_user", "geometry_x", "geometry_y", "last_edited_date", "last_edited_user", "adminaction", "ptaid", "updated", "geom", ).WithParent("fs_mosquitoinspection"), tableAlias: alias, OrganizationID: psql.Quote(alias, "organization_id"), @@ -173,6 +174,7 @@ func buildFSMosquitoinspectionColumns(alias string) fsMosquitoinspectionColumns Adminaction: psql.Quote(alias, "adminaction"), Ptaid: psql.Quote(alias, "ptaid"), Updated: psql.Quote(alias, "updated"), + Geom: psql.Quote(alias, "geom"), } } @@ -240,6 +242,7 @@ type fsMosquitoinspectionColumns struct { Adminaction psql.Expression Ptaid psql.Expression Updated psql.Expression + Geom psql.Expression } func (c fsMosquitoinspectionColumns) Alias() string { @@ -315,10 +318,11 @@ type FSMosquitoinspectionSetter struct { Adminaction omitnull.Val[string] `db:"adminaction" ` Ptaid omitnull.Val[string] `db:"ptaid" ` Updated omit.Val[time.Time] `db:"updated" ` + Geom omitnull.Val[string] `db:"geom" ` } func (s FSMosquitoinspectionSetter) SetColumns() []string { - vals := make([]string, 0, 61) + vals := make([]string, 0, 62) if s.OrganizationID.IsValue() { vals = append(vals, "organization_id") } @@ -502,6 +506,9 @@ func (s FSMosquitoinspectionSetter) SetColumns() []string { if s.Updated.IsValue() { vals = append(vals, "updated") } + if !s.Geom.IsUnset() { + vals = append(vals, "geom") + } return vals } @@ -689,6 +696,9 @@ func (s FSMosquitoinspectionSetter) Overwrite(t *FSMosquitoinspection) { if s.Updated.IsValue() { t.Updated = s.Updated.MustGet() } + if !s.Geom.IsUnset() { + t.Geom = s.Geom.MustGetNull() + } } func (s *FSMosquitoinspectionSetter) Apply(q *dialect.InsertQuery) { @@ -697,7 +707,7 @@ func (s *FSMosquitoinspectionSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 61) + vals := make([]bob.Expression, 62) if s.OrganizationID.IsValue() { vals[0] = psql.Arg(s.OrganizationID.MustGet()) } else { @@ -1064,6 +1074,12 @@ func (s *FSMosquitoinspectionSetter) Apply(q *dialect.InsertQuery) { vals[60] = psql.Raw("DEFAULT") } + if !s.Geom.IsUnset() { + vals[61] = psql.Arg(s.Geom.MustGetNull()) + } else { + vals[61] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -1073,7 +1089,7 @@ func (s FSMosquitoinspectionSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s FSMosquitoinspectionSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 61) + exprs := make([]bob.Expression, 0, 62) if s.OrganizationID.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -1502,6 +1518,13 @@ func (s FSMosquitoinspectionSetter) Expressions(prefix ...string) []bob.Expressi }}) } + if !s.Geom.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "geom")...), + psql.Arg(s.Geom), + }}) + } + return exprs } @@ -1862,6 +1885,7 @@ type fsMosquitoinspectionWhere[Q psql.Filterable] struct { Adminaction psql.WhereNullMod[Q, string] Ptaid psql.WhereNullMod[Q, string] Updated psql.WhereMod[Q, time.Time] + Geom psql.WhereNullMod[Q, string] } func (fsMosquitoinspectionWhere[Q]) AliasedAs(alias string) fsMosquitoinspectionWhere[Q] { @@ -1931,6 +1955,7 @@ func buildFSMosquitoinspectionWhere[Q psql.Filterable](cols fsMosquitoinspection Adminaction: psql.WhereNull[Q, string](cols.Adminaction), Ptaid: psql.WhereNull[Q, string](cols.Ptaid), Updated: psql.Where[Q, time.Time](cols.Updated), + Geom: psql.WhereNull[Q, string](cols.Geom), } } diff --git a/models/fs_pointlocation.bob.go b/models/fs_pointlocation.bob.go index 2b1bfca5..b05daeea 100644 --- a/models/fs_pointlocation.bob.go +++ b/models/fs_pointlocation.bob.go @@ -74,6 +74,7 @@ type FSPointlocation struct { Scalarpriority null.Val[int64] `db:"scalarpriority" ` Sourcestatus null.Val[string] `db:"sourcestatus" ` Updated time.Time `db:"updated" ` + Geom null.Val[string] `db:"geom" ` R fsPointlocationR `db:"-" ` } @@ -96,7 +97,7 @@ type fsPointlocationR struct { func buildFSPointlocationColumns(alias string) fsPointlocationColumns { return fsPointlocationColumns{ ColumnsExpr: expr.NewColumnsExpr( - "organization_id", "accessdesc", "active", "comments", "creationdate", "creator", "description", "externalid", "editdate", "editor", "globalid", "habitat", "jurisdiction", "larvinspectinterval", "lastinspectactiontaken", "lastinspectactivity", "lastinspectavglarvae", "lastinspectavgpupae", "lastinspectbreeding", "lastinspectconditions", "lastinspectdate", "lastinspectfieldspecies", "lastinspectlstages", "lasttreatactivity", "lasttreatdate", "lasttreatproduct", "lasttreatqty", "lasttreatqtyunit", "locationnumber", "name", "nextactiondatescheduled", "objectid", "priority", "stype", "symbology", "usetype", "waterorigin", "x", "y", "zone", "zone2", "geometry_x", "geometry_y", "assignedtech", "deactivate_reason", "scalarpriority", "sourcestatus", "updated", + "organization_id", "accessdesc", "active", "comments", "creationdate", "creator", "description", "externalid", "editdate", "editor", "globalid", "habitat", "jurisdiction", "larvinspectinterval", "lastinspectactiontaken", "lastinspectactivity", "lastinspectavglarvae", "lastinspectavgpupae", "lastinspectbreeding", "lastinspectconditions", "lastinspectdate", "lastinspectfieldspecies", "lastinspectlstages", "lasttreatactivity", "lasttreatdate", "lasttreatproduct", "lasttreatqty", "lasttreatqtyunit", "locationnumber", "name", "nextactiondatescheduled", "objectid", "priority", "stype", "symbology", "usetype", "waterorigin", "x", "y", "zone", "zone2", "geometry_x", "geometry_y", "assignedtech", "deactivate_reason", "scalarpriority", "sourcestatus", "updated", "geom", ).WithParent("fs_pointlocation"), tableAlias: alias, OrganizationID: psql.Quote(alias, "organization_id"), @@ -147,6 +148,7 @@ func buildFSPointlocationColumns(alias string) fsPointlocationColumns { Scalarpriority: psql.Quote(alias, "scalarpriority"), Sourcestatus: psql.Quote(alias, "sourcestatus"), Updated: psql.Quote(alias, "updated"), + Geom: psql.Quote(alias, "geom"), } } @@ -201,6 +203,7 @@ type fsPointlocationColumns struct { Scalarpriority psql.Expression Sourcestatus psql.Expression Updated psql.Expression + Geom psql.Expression } func (c fsPointlocationColumns) Alias() string { @@ -263,10 +266,11 @@ type FSPointlocationSetter struct { Scalarpriority omitnull.Val[int64] `db:"scalarpriority" ` Sourcestatus omitnull.Val[string] `db:"sourcestatus" ` Updated omit.Val[time.Time] `db:"updated" ` + Geom omitnull.Val[string] `db:"geom" ` } func (s FSPointlocationSetter) SetColumns() []string { - vals := make([]string, 0, 48) + vals := make([]string, 0, 49) if s.OrganizationID.IsValue() { vals = append(vals, "organization_id") } @@ -411,6 +415,9 @@ func (s FSPointlocationSetter) SetColumns() []string { if s.Updated.IsValue() { vals = append(vals, "updated") } + if !s.Geom.IsUnset() { + vals = append(vals, "geom") + } return vals } @@ -559,6 +566,9 @@ func (s FSPointlocationSetter) Overwrite(t *FSPointlocation) { if s.Updated.IsValue() { t.Updated = s.Updated.MustGet() } + if !s.Geom.IsUnset() { + t.Geom = s.Geom.MustGetNull() + } } func (s *FSPointlocationSetter) Apply(q *dialect.InsertQuery) { @@ -567,7 +577,7 @@ func (s *FSPointlocationSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 48) + vals := make([]bob.Expression, 49) if s.OrganizationID.IsValue() { vals[0] = psql.Arg(s.OrganizationID.MustGet()) } else { @@ -856,6 +866,12 @@ func (s *FSPointlocationSetter) Apply(q *dialect.InsertQuery) { vals[47] = psql.Raw("DEFAULT") } + if !s.Geom.IsUnset() { + vals[48] = psql.Arg(s.Geom.MustGetNull()) + } else { + vals[48] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -865,7 +881,7 @@ func (s FSPointlocationSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s FSPointlocationSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 48) + exprs := make([]bob.Expression, 0, 49) if s.OrganizationID.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -1203,6 +1219,13 @@ func (s FSPointlocationSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if !s.Geom.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "geom")...), + psql.Arg(s.Geom), + }}) + } + return exprs } @@ -1550,6 +1573,7 @@ type fsPointlocationWhere[Q psql.Filterable] struct { Scalarpriority psql.WhereNullMod[Q, int64] Sourcestatus psql.WhereNullMod[Q, string] Updated psql.WhereMod[Q, time.Time] + Geom psql.WhereNullMod[Q, string] } func (fsPointlocationWhere[Q]) AliasedAs(alias string) fsPointlocationWhere[Q] { @@ -1606,6 +1630,7 @@ func buildFSPointlocationWhere[Q psql.Filterable](cols fsPointlocationColumns) f Scalarpriority: psql.WhereNull[Q, int64](cols.Scalarpriority), Sourcestatus: psql.WhereNull[Q, string](cols.Sourcestatus), Updated: psql.Where[Q, time.Time](cols.Updated), + Geom: psql.WhereNull[Q, string](cols.Geom), } } diff --git a/models/fs_traplocation.bob.go b/models/fs_traplocation.bob.go index 7e2c38ff..ea4f7d2e 100644 --- a/models/fs_traplocation.bob.go +++ b/models/fs_traplocation.bob.go @@ -60,6 +60,7 @@ type FSTraplocation struct { H3R7 null.Val[string] `db:"h3r7" ` H3R8 null.Val[string] `db:"h3r8" ` Updated time.Time `db:"updated" ` + Geom null.Val[string] `db:"geom" ` R fsTraplocationR `db:"-" ` } @@ -82,7 +83,7 @@ type fsTraplocationR struct { func buildFSTraplocationColumns(alias string) fsTraplocationColumns { return fsTraplocationColumns{ ColumnsExpr: expr.NewColumnsExpr( - "organization_id", "accessdesc", "active", "comments", "creationdate", "creator", "description", "externalid", "editdate", "editor", "gatewaysync", "globalid", "habitat", "locationnumber", "name", "nextactiondatescheduled", "objectid", "priority", "usetype", "zone", "zone2", "created_date", "created_user", "geometry_x", "geometry_y", "last_edited_date", "last_edited_user", "route", "route_order", "set_dow", "vectorsurvsiteid", "h3r7", "h3r8", "updated", + "organization_id", "accessdesc", "active", "comments", "creationdate", "creator", "description", "externalid", "editdate", "editor", "gatewaysync", "globalid", "habitat", "locationnumber", "name", "nextactiondatescheduled", "objectid", "priority", "usetype", "zone", "zone2", "created_date", "created_user", "geometry_x", "geometry_y", "last_edited_date", "last_edited_user", "route", "route_order", "set_dow", "vectorsurvsiteid", "h3r7", "h3r8", "updated", "geom", ).WithParent("fs_traplocation"), tableAlias: alias, OrganizationID: psql.Quote(alias, "organization_id"), @@ -119,6 +120,7 @@ func buildFSTraplocationColumns(alias string) fsTraplocationColumns { H3R7: psql.Quote(alias, "h3r7"), H3R8: psql.Quote(alias, "h3r8"), Updated: psql.Quote(alias, "updated"), + Geom: psql.Quote(alias, "geom"), } } @@ -159,6 +161,7 @@ type fsTraplocationColumns struct { H3R7 psql.Expression H3R8 psql.Expression Updated psql.Expression + Geom psql.Expression } func (c fsTraplocationColumns) Alias() string { @@ -207,10 +210,11 @@ type FSTraplocationSetter struct { H3R7 omitnull.Val[string] `db:"h3r7" ` H3R8 omitnull.Val[string] `db:"h3r8" ` Updated omit.Val[time.Time] `db:"updated" ` + Geom omitnull.Val[string] `db:"geom" ` } func (s FSTraplocationSetter) SetColumns() []string { - vals := make([]string, 0, 34) + vals := make([]string, 0, 35) if s.OrganizationID.IsValue() { vals = append(vals, "organization_id") } @@ -313,6 +317,9 @@ func (s FSTraplocationSetter) SetColumns() []string { if s.Updated.IsValue() { vals = append(vals, "updated") } + if !s.Geom.IsUnset() { + vals = append(vals, "geom") + } return vals } @@ -419,6 +426,9 @@ func (s FSTraplocationSetter) Overwrite(t *FSTraplocation) { if s.Updated.IsValue() { t.Updated = s.Updated.MustGet() } + if !s.Geom.IsUnset() { + t.Geom = s.Geom.MustGetNull() + } } func (s *FSTraplocationSetter) Apply(q *dialect.InsertQuery) { @@ -427,7 +437,7 @@ func (s *FSTraplocationSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 34) + vals := make([]bob.Expression, 35) if s.OrganizationID.IsValue() { vals[0] = psql.Arg(s.OrganizationID.MustGet()) } else { @@ -632,6 +642,12 @@ func (s *FSTraplocationSetter) Apply(q *dialect.InsertQuery) { vals[33] = psql.Raw("DEFAULT") } + if !s.Geom.IsUnset() { + vals[34] = psql.Arg(s.Geom.MustGetNull()) + } else { + vals[34] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -641,7 +657,7 @@ func (s FSTraplocationSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s FSTraplocationSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 34) + exprs := make([]bob.Expression, 0, 35) if s.OrganizationID.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -881,6 +897,13 @@ func (s FSTraplocationSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if !s.Geom.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "geom")...), + psql.Arg(s.Geom), + }}) + } + return exprs } @@ -1214,6 +1237,7 @@ type fsTraplocationWhere[Q psql.Filterable] struct { H3R7 psql.WhereNullMod[Q, string] H3R8 psql.WhereNullMod[Q, string] Updated psql.WhereMod[Q, time.Time] + Geom psql.WhereNullMod[Q, string] } func (fsTraplocationWhere[Q]) AliasedAs(alias string) fsTraplocationWhere[Q] { @@ -1256,6 +1280,7 @@ func buildFSTraplocationWhere[Q psql.Filterable](cols fsTraplocationColumns) fsT H3R7: psql.WhereNull[Q, string](cols.H3R7), H3R8: psql.WhereNull[Q, string](cols.H3R8), Updated: psql.Where[Q, time.Time](cols.Updated), + Geom: psql.WhereNull[Q, string](cols.Geom), } } diff --git a/models/fs_treatment.bob.go b/models/fs_treatment.bob.go index 169ecbe1..d69cf92e 100644 --- a/models/fs_treatment.bob.go +++ b/models/fs_treatment.bob.go @@ -84,6 +84,7 @@ type FSTreatment struct { GeometryY null.Val[float64] `db:"geometry_y" ` TempSitecond null.Val[string] `db:"temp_sitecond" ` Updated time.Time `db:"updated" ` + Geom null.Val[string] `db:"geom" ` R fsTreatmentR `db:"-" ` } @@ -106,7 +107,7 @@ type fsTreatmentR struct { func buildFSTreatmentColumns(alias string) fsTreatmentColumns { return fsTreatmentColumns{ ColumnsExpr: expr.NewColumnsExpr( - "organization_id", "activity", "areaunit", "avetemp", "barrierrouteid", "cbcount", "comments", "containercount", "creationdate", "creator", "enddatetime", "equiptype", "editdate", "editor", "fieldtech", "flowrate", "globalid", "habitat", "insp_id", "invloc", "linelocid", "locationname", "method", "objectid", "pointlocid", "polygonlocid", "product", "ptaid", "qty", "qtyunit", "raingauge", "recordstatus", "reviewed", "reviewedby", "revieweddate", "sdid", "sitecond", "srid", "startdatetime", "targetspecies", "tirecount", "treatacres", "treatarea", "treathectares", "treatmenthours", "treatmentlength", "treatmentlengthunits", "totalcostprodcut", "ulvrouteid", "warningoverride", "winddir", "windspeed", "zone", "zone2", "geometry_x", "geometry_y", "temp_sitecond", "updated", + "organization_id", "activity", "areaunit", "avetemp", "barrierrouteid", "cbcount", "comments", "containercount", "creationdate", "creator", "enddatetime", "equiptype", "editdate", "editor", "fieldtech", "flowrate", "globalid", "habitat", "insp_id", "invloc", "linelocid", "locationname", "method", "objectid", "pointlocid", "polygonlocid", "product", "ptaid", "qty", "qtyunit", "raingauge", "recordstatus", "reviewed", "reviewedby", "revieweddate", "sdid", "sitecond", "srid", "startdatetime", "targetspecies", "tirecount", "treatacres", "treatarea", "treathectares", "treatmenthours", "treatmentlength", "treatmentlengthunits", "totalcostprodcut", "ulvrouteid", "warningoverride", "winddir", "windspeed", "zone", "zone2", "geometry_x", "geometry_y", "temp_sitecond", "updated", "geom", ).WithParent("fs_treatment"), tableAlias: alias, OrganizationID: psql.Quote(alias, "organization_id"), @@ -167,6 +168,7 @@ func buildFSTreatmentColumns(alias string) fsTreatmentColumns { GeometryY: psql.Quote(alias, "geometry_y"), TempSitecond: psql.Quote(alias, "temp_sitecond"), Updated: psql.Quote(alias, "updated"), + Geom: psql.Quote(alias, "geom"), } } @@ -231,6 +233,7 @@ type fsTreatmentColumns struct { GeometryY psql.Expression TempSitecond psql.Expression Updated psql.Expression + Geom psql.Expression } func (c fsTreatmentColumns) Alias() string { @@ -303,10 +306,11 @@ type FSTreatmentSetter struct { GeometryY omitnull.Val[float64] `db:"geometry_y" ` TempSitecond omitnull.Val[string] `db:"temp_sitecond" ` Updated omit.Val[time.Time] `db:"updated" ` + Geom omitnull.Val[string] `db:"geom" ` } func (s FSTreatmentSetter) SetColumns() []string { - vals := make([]string, 0, 58) + vals := make([]string, 0, 59) if s.OrganizationID.IsValue() { vals = append(vals, "organization_id") } @@ -481,6 +485,9 @@ func (s FSTreatmentSetter) SetColumns() []string { if s.Updated.IsValue() { vals = append(vals, "updated") } + if !s.Geom.IsUnset() { + vals = append(vals, "geom") + } return vals } @@ -659,6 +666,9 @@ func (s FSTreatmentSetter) Overwrite(t *FSTreatment) { if s.Updated.IsValue() { t.Updated = s.Updated.MustGet() } + if !s.Geom.IsUnset() { + t.Geom = s.Geom.MustGetNull() + } } func (s *FSTreatmentSetter) Apply(q *dialect.InsertQuery) { @@ -667,7 +677,7 @@ func (s *FSTreatmentSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 58) + vals := make([]bob.Expression, 59) if s.OrganizationID.IsValue() { vals[0] = psql.Arg(s.OrganizationID.MustGet()) } else { @@ -1016,6 +1026,12 @@ func (s *FSTreatmentSetter) Apply(q *dialect.InsertQuery) { vals[57] = psql.Raw("DEFAULT") } + if !s.Geom.IsUnset() { + vals[58] = psql.Arg(s.Geom.MustGetNull()) + } else { + vals[58] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -1025,7 +1041,7 @@ func (s FSTreatmentSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s FSTreatmentSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 58) + exprs := make([]bob.Expression, 0, 59) if s.OrganizationID.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -1433,6 +1449,13 @@ func (s FSTreatmentSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if !s.Geom.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "geom")...), + psql.Arg(s.Geom), + }}) + } + return exprs } @@ -1790,6 +1813,7 @@ type fsTreatmentWhere[Q psql.Filterable] struct { GeometryY psql.WhereNullMod[Q, float64] TempSitecond psql.WhereNullMod[Q, string] Updated psql.WhereMod[Q, time.Time] + Geom psql.WhereNullMod[Q, string] } func (fsTreatmentWhere[Q]) AliasedAs(alias string) fsTreatmentWhere[Q] { @@ -1856,6 +1880,7 @@ func buildFSTreatmentWhere[Q psql.Filterable](cols fsTreatmentColumns) fsTreatme GeometryY: psql.WhereNull[Q, float64](cols.GeometryY), TempSitecond: psql.WhereNull[Q, string](cols.TempSitecond), Updated: psql.Where[Q, time.Time](cols.Updated), + Geom: psql.WhereNull[Q, string](cols.Geom), } } diff --git a/models/h3_aggregation.bob.go b/models/h3_aggregation.bob.go index 3a01527a..64d90800 100644 --- a/models/h3_aggregation.bob.go +++ b/models/h3_aggregation.bob.go @@ -9,7 +9,9 @@ import ( "io" enums "github.com/Gleipnir-Technology/nidus-sync/enums" + "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/psql" "github.com/stephenafamo/bob/dialect/psql/dialect" @@ -26,10 +28,11 @@ import ( type H3Aggregation struct { ID int32 `db:"id,pk" ` Cell string `db:"cell" ` - Resolution int32 `db:"resolution" ` Count int32 `db:"count_" ` - Type enums.H3aggregationtype `db:"type_" ` + Geometry null.Val[string] `db:"geometry" ` OrganizationID int32 `db:"organization_id" ` + Resolution int32 `db:"resolution" ` + Type enums.H3aggregationtype `db:"type_" ` R h3AggregationR `db:"-" ` } @@ -52,15 +55,16 @@ type h3AggregationR struct { func buildH3AggregationColumns(alias string) h3AggregationColumns { return h3AggregationColumns{ ColumnsExpr: expr.NewColumnsExpr( - "id", "cell", "resolution", "count_", "type_", "organization_id", + "id", "cell", "count_", "geometry", "organization_id", "resolution", "type_", ).WithParent("h3_aggregation"), tableAlias: alias, ID: psql.Quote(alias, "id"), Cell: psql.Quote(alias, "cell"), - Resolution: psql.Quote(alias, "resolution"), Count: psql.Quote(alias, "count_"), - Type: psql.Quote(alias, "type_"), + Geometry: psql.Quote(alias, "geometry"), OrganizationID: psql.Quote(alias, "organization_id"), + Resolution: psql.Quote(alias, "resolution"), + Type: psql.Quote(alias, "type_"), } } @@ -69,10 +73,11 @@ type h3AggregationColumns struct { tableAlias string ID psql.Expression Cell psql.Expression - Resolution psql.Expression Count psql.Expression - Type psql.Expression + Geometry psql.Expression OrganizationID psql.Expression + Resolution psql.Expression + Type psql.Expression } func (c h3AggregationColumns) Alias() string { @@ -89,32 +94,36 @@ func (h3AggregationColumns) AliasedAs(alias string) h3AggregationColumns { type H3AggregationSetter struct { ID omit.Val[int32] `db:"id,pk" ` Cell omit.Val[string] `db:"cell" ` - Resolution omit.Val[int32] `db:"resolution" ` Count omit.Val[int32] `db:"count_" ` - Type omit.Val[enums.H3aggregationtype] `db:"type_" ` + Geometry omitnull.Val[string] `db:"geometry" ` OrganizationID omit.Val[int32] `db:"organization_id" ` + Resolution omit.Val[int32] `db:"resolution" ` + Type omit.Val[enums.H3aggregationtype] `db:"type_" ` } func (s H3AggregationSetter) SetColumns() []string { - vals := make([]string, 0, 6) + vals := make([]string, 0, 7) if s.ID.IsValue() { vals = append(vals, "id") } if s.Cell.IsValue() { vals = append(vals, "cell") } - if s.Resolution.IsValue() { - vals = append(vals, "resolution") - } if s.Count.IsValue() { vals = append(vals, "count_") } - if s.Type.IsValue() { - vals = append(vals, "type_") + if !s.Geometry.IsUnset() { + vals = append(vals, "geometry") } if s.OrganizationID.IsValue() { vals = append(vals, "organization_id") } + if s.Resolution.IsValue() { + vals = append(vals, "resolution") + } + if s.Type.IsValue() { + vals = append(vals, "type_") + } return vals } @@ -125,18 +134,21 @@ func (s H3AggregationSetter) Overwrite(t *H3Aggregation) { if s.Cell.IsValue() { t.Cell = s.Cell.MustGet() } - if s.Resolution.IsValue() { - t.Resolution = s.Resolution.MustGet() - } if s.Count.IsValue() { t.Count = s.Count.MustGet() } - if s.Type.IsValue() { - t.Type = s.Type.MustGet() + if !s.Geometry.IsUnset() { + t.Geometry = s.Geometry.MustGetNull() } if s.OrganizationID.IsValue() { t.OrganizationID = s.OrganizationID.MustGet() } + if s.Resolution.IsValue() { + t.Resolution = s.Resolution.MustGet() + } + if s.Type.IsValue() { + t.Type = s.Type.MustGet() + } } func (s *H3AggregationSetter) Apply(q *dialect.InsertQuery) { @@ -145,7 +157,7 @@ func (s *H3AggregationSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 6) + vals := make([]bob.Expression, 7) if s.ID.IsValue() { vals[0] = psql.Arg(s.ID.MustGet()) } else { @@ -158,30 +170,36 @@ func (s *H3AggregationSetter) Apply(q *dialect.InsertQuery) { vals[1] = psql.Raw("DEFAULT") } - if s.Resolution.IsValue() { - vals[2] = psql.Arg(s.Resolution.MustGet()) + if s.Count.IsValue() { + vals[2] = psql.Arg(s.Count.MustGet()) } else { vals[2] = psql.Raw("DEFAULT") } - if s.Count.IsValue() { - vals[3] = psql.Arg(s.Count.MustGet()) + if !s.Geometry.IsUnset() { + vals[3] = psql.Arg(s.Geometry.MustGetNull()) } else { vals[3] = psql.Raw("DEFAULT") } - if s.Type.IsValue() { - vals[4] = psql.Arg(s.Type.MustGet()) + if s.OrganizationID.IsValue() { + vals[4] = psql.Arg(s.OrganizationID.MustGet()) } else { vals[4] = psql.Raw("DEFAULT") } - if s.OrganizationID.IsValue() { - vals[5] = psql.Arg(s.OrganizationID.MustGet()) + if s.Resolution.IsValue() { + vals[5] = psql.Arg(s.Resolution.MustGet()) } else { vals[5] = psql.Raw("DEFAULT") } + if s.Type.IsValue() { + vals[6] = psql.Arg(s.Type.MustGet()) + } else { + vals[6] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -191,7 +209,7 @@ func (s H3AggregationSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s H3AggregationSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 6) + exprs := make([]bob.Expression, 0, 7) if s.ID.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -207,13 +225,6 @@ func (s H3AggregationSetter) Expressions(prefix ...string) []bob.Expression { }}) } - if s.Resolution.IsValue() { - exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ - psql.Quote(append(prefix, "resolution")...), - psql.Arg(s.Resolution), - }}) - } - if s.Count.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ psql.Quote(append(prefix, "count_")...), @@ -221,10 +232,10 @@ func (s H3AggregationSetter) Expressions(prefix ...string) []bob.Expression { }}) } - if s.Type.IsValue() { + if !s.Geometry.IsUnset() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ - psql.Quote(append(prefix, "type_")...), - psql.Arg(s.Type), + psql.Quote(append(prefix, "geometry")...), + psql.Arg(s.Geometry), }}) } @@ -235,6 +246,20 @@ func (s H3AggregationSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if s.Resolution.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "resolution")...), + psql.Arg(s.Resolution), + }}) + } + + if s.Type.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "type_")...), + psql.Arg(s.Type), + }}) + } + return exprs } @@ -536,10 +561,11 @@ func (h3Aggregation0 *H3Aggregation) AttachOrganization(ctx context.Context, exe type h3AggregationWhere[Q psql.Filterable] struct { ID psql.WhereMod[Q, int32] Cell psql.WhereMod[Q, string] - Resolution psql.WhereMod[Q, int32] Count psql.WhereMod[Q, int32] - Type psql.WhereMod[Q, enums.H3aggregationtype] + Geometry psql.WhereNullMod[Q, string] OrganizationID psql.WhereMod[Q, int32] + Resolution psql.WhereMod[Q, int32] + Type psql.WhereMod[Q, enums.H3aggregationtype] } func (h3AggregationWhere[Q]) AliasedAs(alias string) h3AggregationWhere[Q] { @@ -550,10 +576,11 @@ func buildH3AggregationWhere[Q psql.Filterable](cols h3AggregationColumns) h3Agg return h3AggregationWhere[Q]{ ID: psql.Where[Q, int32](cols.ID), Cell: psql.Where[Q, string](cols.Cell), - Resolution: psql.Where[Q, int32](cols.Resolution), Count: psql.Where[Q, int32](cols.Count), - Type: psql.Where[Q, enums.H3aggregationtype](cols.Type), + Geometry: psql.WhereNull[Q, string](cols.Geometry), OrganizationID: psql.Where[Q, int32](cols.OrganizationID), + Resolution: psql.Where[Q, int32](cols.Resolution), + Type: psql.Where[Q, enums.H3aggregationtype](cols.Type), } } diff --git a/sql/test_utils.bob_test.go b/sql/test_utils.bob_test.go index a6b26c90..4d5aa6c0 100644 --- a/sql/test_utils.bob_test.go +++ b/sql/test_utils.bob_test.go @@ -10,6 +10,7 @@ import ( enums "github.com/Gleipnir-Technology/nidus-sync/enums" "github.com/jaswdr/faker/v2" + "github.com/shopspring/decimal" "github.com/stephenafamo/bob" pg_query "github.com/wasilibs/go-pgquery" ) @@ -28,6 +29,37 @@ func formatQuery(s string) (string, error) { var defaultFaker = faker.New() +func random_decimal_Decimal(f *faker.Faker, limits ...string) decimal.Decimal { + if f == nil { + f = &defaultFaker + } + + var precision int64 = 7 + var scale int64 = 3 + + if len(limits) > 0 { + precision, _ = strconv.ParseInt(limits[0], 10, 32) + } + + if len(limits) > 1 { + scale, _ = strconv.ParseInt(limits[1], 10, 32) + } + + baseVal := f.Float32(10, -1, 1) + for baseVal == -1 || baseVal == 0 || baseVal == 1 { + baseVal = f.Float32(10, -1, 1) + } + + precisionDecimal, _ := decimal.NewFromInt(10).PowInt32(int32(precision)) + val := decimal. + NewFromFloat32(baseVal). + Mul(precisionDecimal). + Shift(int32(-1 * scale)). + RoundDown(int32(scale)) + + return val +} + func random_enums_Arcgislicensetype(f *faker.Faker, limits ...string) enums.Arcgislicensetype { if f == nil { f = &defaultFaker @@ -56,6 +88,14 @@ func random_int32(f *faker.Faker, limits ...string) int32 { return f.Int32() } +func random_int64(f *faker.Faker, limits ...string) int64 { + if f == nil { + f = &defaultFaker + } + + return f.Int64() +} + func random_string(f *faker.Faker, limits ...string) string { if f == nil { f = &defaultFaker diff --git a/sql/trapcount_by_location_id.bob.go b/sql/trapcount_by_location_id.bob.go new file mode 100644 index 00000000..c1ec643d --- /dev/null +++ b/sql/trapcount_by_location_id.bob.go @@ -0,0 +1,114 @@ +// Code generated by BobGen psql v0.41.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package sql + +import ( + "context" + _ "embed" + "io" + "iter" + + "github.com/aarondl/opt/null" + "github.com/shopspring/decimal" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + "github.com/stephenafamo/bob/dialect/psql/dialect" + "github.com/stephenafamo/bob/expr" + "github.com/stephenafamo/bob/orm" + "github.com/stephenafamo/scan" +) + +//go:embed trapcount_by_location_id.bob.sql +var formattedQueries_trapcount_by_location_id string + +var trapCountByLocationIDSQL = formattedQueries_trapcount_by_location_id[159:580] + +type TrapCountByLocationIDQuery = orm.ModQuery[*dialect.SelectQuery, trapCountByLocationID, TrapCountByLocationIDRow, []TrapCountByLocationIDRow, trapCountByLocationIDTransformer] + +func TrapCountByLocationID(OrganizationID int32, LocID []string) *TrapCountByLocationIDQuery { + var expressionTypArgs trapCountByLocationID + + expressionTypArgs.OrganizationID = psql.Arg(OrganizationID) + expressionTypArgs.LocID = expr.ToArgs(LocID...) + + return &TrapCountByLocationIDQuery{ + Query: orm.Query[trapCountByLocationID, TrapCountByLocationIDRow, []TrapCountByLocationIDRow, trapCountByLocationIDTransformer]{ + ExecQuery: orm.ExecQuery[trapCountByLocationID]{ + BaseQuery: bob.BaseQuery[trapCountByLocationID]{ + Expression: expressionTypArgs, + Dialect: dialect.Dialect, + QueryType: bob.QueryTypeSelect, + }, + }, + Scanner: func(context.Context, []string) (func(*scan.Row) (any, error), func(any) (TrapCountByLocationIDRow, error)) { + return func(row *scan.Row) (any, error) { + var t TrapCountByLocationIDRow + row.ScheduleScanByIndex(0, &t.TrapdataGlobalid) + row.ScheduleScanByIndex(1, &t.TrapdataEnddate) + row.ScheduleScanByIndex(2, &t.TotalFemales) + row.ScheduleScanByIndex(3, &t.TotalMales) + row.ScheduleScanByIndex(4, &t.Total) + return &t, nil + }, func(v any) (TrapCountByLocationIDRow, error) { + return *(v.(*TrapCountByLocationIDRow)), nil + } + }, + }, + Mod: bob.ModFunc[*dialect.SelectQuery](func(q *dialect.SelectQuery) { + q.AppendSelect(expressionTypArgs.subExpr(12, 223)) + q.SetTable(expressionTypArgs.subExpr(234, 318)) + q.AppendWhere(expressionTypArgs.subExpr(330, 379)) + q.AppendGroup(expressionTypArgs.subExpr(394, 421)) + }), + } +} + +type TrapCountByLocationIDRow = struct { + TrapdataGlobalid string `db:"trapdata_globalid"` + TrapdataEnddate null.Val[int64] `db:"trapdata_enddate"` + TotalFemales decimal.Decimal `db:"total_females"` + TotalMales int64 `db:"total_males"` + Total decimal.Decimal `db:"total"` +} + +type trapCountByLocationIDTransformer = bob.SliceTransformer[TrapCountByLocationIDRow, []TrapCountByLocationIDRow] + +type trapCountByLocationID struct { + OrganizationID bob.Expression + LocID bob.Expression +} + +func (o trapCountByLocationID) args() iter.Seq[orm.ArgWithPosition] { + return func(yield func(arg orm.ArgWithPosition) bool) { + if !yield(orm.ArgWithPosition{ + Name: "organizationID", + Start: 351, + Stop: 353, + Expression: o.OrganizationID, + }) { + return + } + + if !yield(orm.ArgWithPosition{ + Name: "locID", + Start: 376, + Stop: 378, + Expression: o.LocID, + }) { + return + } + } +} + +func (o trapCountByLocationID) raw(from, to int) string { + return trapCountByLocationIDSQL[from:to] +} + +func (o trapCountByLocationID) subExpr(from, to int) bob.Expression { + return orm.ArgsToExpression(trapCountByLocationIDSQL, from, to, o.args()) +} + +func (o trapCountByLocationID) WriteSQL(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { + return o.subExpr(0, len(trapCountByLocationIDSQL)).WriteSQL(ctx, w, d, start) +} diff --git a/sql/trapcount_by_location_id.bob.sql b/sql/trapcount_by_location_id.bob.sql new file mode 100644 index 00000000..ebb88083 --- /dev/null +++ b/sql/trapcount_by_location_id.bob.sql @@ -0,0 +1,19 @@ +-- Code generated by BobGen psql v0.41.1. DO NOT EDIT. +-- This file is meant to be re-generated in place and/or deleted at any time. + +-- TrapCountByLocationID +SELECT + td.globalid AS trapdata_globalid, + td.enddatetime AS trapdata_enddate, + COALESCE(SUM(sa.females), 0) AS total_females, + COALESCE(SUM(sa.males), 0) AS total_males, + COALESCE(SUM(sa.total), 0) AS total +FROM + fs_trapdata td +LEFT JOIN + fs_speciesabundance sa ON td.globalid = sa.trapdata_id +WHERE + td.organization_id = $1 + AND td.loc_id IN ($2) +GROUP BY + td.globalid, td.enddatetime; diff --git a/sql/trapcount_by_location_id.bob_test.go b/sql/trapcount_by_location_id.bob_test.go new file mode 100644 index 00000000..03dcb09d --- /dev/null +++ b/sql/trapcount_by_location_id.bob_test.go @@ -0,0 +1,111 @@ +// Code generated by BobGen psql v0.41.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package sql + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + testutils "github.com/stephenafamo/bob/test/utils" +) + +func TestTrapCountByLocationID(t *testing.T) { + t.Run("Base", func(t *testing.T) { + var sb strings.Builder + + query := TrapCountByLocationID(random_int32(nil), []string{random_string(nil)}) + + if _, err := query.WriteQuery(t.Context(), &sb, 1); err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(trapCountByLocationIDSQL, sb.String()); diff != "" { + t.Fatalf("unexpected result (-got +want):\n%s", diff) + } + }) + + t.Run("Mod", func(t *testing.T) { + var sb strings.Builder + + query := TrapCountByLocationID(random_int32(nil), []string{random_string(nil)}) + + if _, err := psql.Select(query).WriteQuery(t.Context(), &sb, 1); err != nil { + t.Fatal(err) + } + + queryDiff, err := testutils.QueryDiff(trapCountByLocationIDSQL, sb.String(), formatQuery) + if err != nil { + t.Fatal(err) + } + if queryDiff != "" { + fmt.Println(sb.String()) + t.Fatalf("unexpected result (-got +want):\n%s", queryDiff) + } + }) + + t.Run("Scanning", func(t *testing.T) { + if testDB == nil { + t.Skip("skipping test, no DSN provided") + } + + ctxTx, cancel := context.WithCancel(t.Context()) + defer cancel() + + tx, err := testDB.Begin(ctxTx) + if err != nil { + t.Fatalf("Error starting transaction: %v", err) + } + + defer func() { + if err := tx.Rollback(ctxTx); err != nil { + t.Fatalf("Error rolling back transaction: %v", err) + } + }() + + query, args, err := bob.Build(ctxTx, psql.Select(TrapCountByLocationID(random_int32(nil), []string{random_string(nil)}))) + if err != nil { + t.Fatal(err) + } + + rows, err := tx.QueryContext(ctxTx, query, args...) + if err != nil { + t.Fatal(err) + } + defer rows.Close() + + columns, err := rows.Columns() + if err != nil { + t.Fatal(err) + } + + if len(columns) != 5 { + t.Fatalf("expected %d columns, got %d", 5, len(columns)) + } + + if columns[0] != "trapdata_globalid" { + t.Fatalf("expected column %d to be %s, got %s", 0, "trapdata_globalid", columns[0]) + } + + if columns[1] != "trapdata_enddate" { + t.Fatalf("expected column %d to be %s, got %s", 1, "trapdata_enddate", columns[1]) + } + + if columns[2] != "total_females" { + t.Fatalf("expected column %d to be %s, got %s", 2, "total_females", columns[2]) + } + + if columns[3] != "total_males" { + t.Fatalf("expected column %d to be %s, got %s", 3, "total_males", columns[3]) + } + + if columns[4] != "total" { + t.Fatalf("expected column %d to be %s, got %s", 4, "total", columns[4]) + } + }) +} diff --git a/sql/trapcount_by_location_id.sql b/sql/trapcount_by_location_id.sql new file mode 100644 index 00000000..daa69e72 --- /dev/null +++ b/sql/trapcount_by_location_id.sql @@ -0,0 +1,17 @@ +-- TrapCountByLocationID +SELECT + td.loc_id AS trapdata_globalid, + td.enddatetime AS trapdata_enddate, + COALESCE(SUM(sa.females), 0) AS total_females, + COALESCE(SUM(sa.males), 0) AS total_males, + COALESCE(SUM(sa.total), 0) AS total +FROM + fs_trapdata td +LEFT JOIN + fs_speciesabundance sa ON td.globalid = sa.trapdata_id +WHERE + td.organization_id = $1 + AND td.loc_id IN ($2) +GROUP BY + td.globalid, td.enddatetime; + diff --git a/sql/traplocation_by_source_id.bob.go b/sql/traplocation_by_source_id.bob.go new file mode 100644 index 00000000..a2284117 --- /dev/null +++ b/sql/traplocation_by_source_id.bob.go @@ -0,0 +1,106 @@ +// Code generated by BobGen psql v0.41.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package sql + +import ( + "context" + _ "embed" + "io" + "iter" + + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + "github.com/stephenafamo/bob/dialect/psql/dialect" + "github.com/stephenafamo/bob/orm" + "github.com/stephenafamo/scan" +) + +//go:embed traplocation_by_source_id.bob.sql +var formattedQueries_traplocation_by_source_id string + +var trapLocationBySourceIDSQL = formattedQueries_traplocation_by_source_id[160:411] + +type TrapLocationBySourceIDQuery = orm.ModQuery[*dialect.SelectQuery, trapLocationBySourceID, TrapLocationBySourceIDRow, []TrapLocationBySourceIDRow, trapLocationBySourceIDTransformer] + +func TrapLocationBySourceID(OrganizationID int32, Globalid string) *TrapLocationBySourceIDQuery { + var expressionTypArgs trapLocationBySourceID + + expressionTypArgs.OrganizationID = psql.Arg(OrganizationID) + expressionTypArgs.Globalid = psql.Arg(Globalid) + + return &TrapLocationBySourceIDQuery{ + Query: orm.Query[trapLocationBySourceID, TrapLocationBySourceIDRow, []TrapLocationBySourceIDRow, trapLocationBySourceIDTransformer]{ + ExecQuery: orm.ExecQuery[trapLocationBySourceID]{ + BaseQuery: bob.BaseQuery[trapLocationBySourceID]{ + Expression: expressionTypArgs, + Dialect: dialect.Dialect, + QueryType: bob.QueryTypeSelect, + }, + }, + Scanner: func(context.Context, []string) (func(*scan.Row) (any, error), func(any) (TrapLocationBySourceIDRow, error)) { + return func(row *scan.Row) (any, error) { + var t TrapLocationBySourceIDRow + row.ScheduleScanByIndex(0, &t.TrapLocationGlobalid) + row.ScheduleScanByIndex(1, &t.Distance) + return &t, nil + }, func(v any) (TrapLocationBySourceIDRow, error) { + return *(v.(*TrapLocationBySourceIDRow)), nil + } + }, + }, + Mod: bob.ModFunc[*dialect.SelectQuery](func(q *dialect.SelectQuery) { + q.CombinedLimit.SetLimit(psql.Raw("4")) + q.AppendSelect(expressionTypArgs.subExpr(9, 90)) + q.SetTable(expressionTypArgs.subExpr(98, 148)) + q.AppendWhere(expressionTypArgs.subExpr(157, 202)) + q.CombinedOrder.AppendOrder(expressionTypArgs.subExpr(214, 243)) + }), + } +} + +type TrapLocationBySourceIDRow = struct { + TrapLocationGlobalid string `db:"trap_location_globalid"` + Distance string `db:"distance"` +} + +type trapLocationBySourceIDTransformer = bob.SliceTransformer[TrapLocationBySourceIDRow, []TrapLocationBySourceIDRow] + +type trapLocationBySourceID struct { + OrganizationID bob.Expression + Globalid bob.Expression +} + +func (o trapLocationBySourceID) args() iter.Seq[orm.ArgWithPosition] { + return func(yield func(arg orm.ArgWithPosition) bool) { + if !yield(orm.ArgWithPosition{ + Name: "organizationID", + Start: 178, + Stop: 180, + Expression: o.OrganizationID, + }) { + return + } + + if !yield(orm.ArgWithPosition{ + Name: "globalid", + Start: 200, + Stop: 202, + Expression: o.Globalid, + }) { + return + } + } +} + +func (o trapLocationBySourceID) raw(from, to int) string { + return trapLocationBySourceIDSQL[from:to] +} + +func (o trapLocationBySourceID) subExpr(from, to int) bob.Expression { + return orm.ArgsToExpression(trapLocationBySourceIDSQL, from, to, o.args()) +} + +func (o trapLocationBySourceID) WriteSQL(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) { + return o.subExpr(0, len(trapLocationBySourceIDSQL)).WriteSQL(ctx, w, d, start) +} diff --git a/sql/traplocation_by_source_id.bob.sql b/sql/traplocation_by_source_id.bob.sql new file mode 100644 index 00000000..6d60cfd8 --- /dev/null +++ b/sql/traplocation_by_source_id.bob.sql @@ -0,0 +1,17 @@ +-- Code generated by BobGen psql v0.41.1. DO NOT EDIT. +-- This file is meant to be re-generated in place and/or deleted at any time. + +-- TrapLocationBySourceID +SELECT + tl.globalid AS trap_location_globalid, + ST_Distance(pl.geom, tl.geom) AS distance +FROM + fs_pointlocation pl +CROSS JOIN + fs_traplocation tl +WHERE + tl.organization_id = $1 AND + pl.globalid = $2 +ORDER BY + ST_Distance(pl.geom, tl.geom) +LIMIT 4; diff --git a/sql/traplocation_by_source_id.bob_test.go b/sql/traplocation_by_source_id.bob_test.go new file mode 100644 index 00000000..c5f62283 --- /dev/null +++ b/sql/traplocation_by_source_id.bob_test.go @@ -0,0 +1,99 @@ +// Code generated by BobGen psql v0.41.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package sql + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + testutils "github.com/stephenafamo/bob/test/utils" +) + +func TestTrapLocationBySourceID(t *testing.T) { + t.Run("Base", func(t *testing.T) { + var sb strings.Builder + + query := TrapLocationBySourceID(random_int32(nil), random_string(nil)) + + if _, err := query.WriteQuery(t.Context(), &sb, 1); err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(trapLocationBySourceIDSQL, sb.String()); diff != "" { + t.Fatalf("unexpected result (-got +want):\n%s", diff) + } + }) + + t.Run("Mod", func(t *testing.T) { + var sb strings.Builder + + query := TrapLocationBySourceID(random_int32(nil), random_string(nil)) + + if _, err := psql.Select(query).WriteQuery(t.Context(), &sb, 1); err != nil { + t.Fatal(err) + } + + queryDiff, err := testutils.QueryDiff(trapLocationBySourceIDSQL, sb.String(), formatQuery) + if err != nil { + t.Fatal(err) + } + if queryDiff != "" { + fmt.Println(sb.String()) + t.Fatalf("unexpected result (-got +want):\n%s", queryDiff) + } + }) + + t.Run("Scanning", func(t *testing.T) { + if testDB == nil { + t.Skip("skipping test, no DSN provided") + } + + ctxTx, cancel := context.WithCancel(t.Context()) + defer cancel() + + tx, err := testDB.Begin(ctxTx) + if err != nil { + t.Fatalf("Error starting transaction: %v", err) + } + + defer func() { + if err := tx.Rollback(ctxTx); err != nil { + t.Fatalf("Error rolling back transaction: %v", err) + } + }() + + query, args, err := bob.Build(ctxTx, psql.Select(TrapLocationBySourceID(random_int32(nil), random_string(nil)))) + if err != nil { + t.Fatal(err) + } + + rows, err := tx.QueryContext(ctxTx, query, args...) + if err != nil { + t.Fatal(err) + } + defer rows.Close() + + columns, err := rows.Columns() + if err != nil { + t.Fatal(err) + } + + if len(columns) != 2 { + t.Fatalf("expected %d columns, got %d", 2, len(columns)) + } + + if columns[0] != "trap_location_globalid" { + t.Fatalf("expected column %d to be %s, got %s", 0, "trap_location_globalid", columns[0]) + } + + if columns[1] != "distance" { + t.Fatalf("expected column %d to be %s, got %s", 1, "distance", columns[1]) + } + }) +} diff --git a/sql/traplocation_by_source_id.sql b/sql/traplocation_by_source_id.sql new file mode 100644 index 00000000..0cfdf89a --- /dev/null +++ b/sql/traplocation_by_source_id.sql @@ -0,0 +1,14 @@ +-- TrapLocationBySourceID +SELECT + tl.globalid AS trap_location_globalid, + ST_Distance(pl.geom, tl.geom) AS distance +FROM + fs_pointlocation pl +CROSS JOIN + fs_traplocation tl +WHERE + tl.organization_id = $1 AND + pl.globalid = $2 +ORDER BY + ST_Distance(pl.geom, tl.geom) +LIMIT 4 diff --git a/templates/source.html b/templates/source.html index 345844d2..c273c867 100644 --- a/templates/source.html +++ b/templates/source.html @@ -57,6 +57,10 @@
Source ID: {{ .Source.GlobalID }}
+ + + + @@ -317,69 +321,21 @@ + {{ range .Traps }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {{ range .Counts }} + + + + + {{ end }} + {{ end }}
Location:{{ .Source.LatLng|latLngDisplay }}
Access: {{ .Source.AccessDescription }}
TR-1050.2 mi04/17/202337
04/10/202352
04/03/202361
TR-1080.4 mi04/17/202322
04/10/202335
04/03/202341
TR-1120.6 mi04/17/202318
04/10/202324
04/03/202327
TR-1170.8 mi04/17/202312
04/10/202319
04/03/202315{{ .ID }}{{ .Distance }}
{{ .Ended|timeSince }}{{ .Total }}