diff --git a/api/routes.go b/api/routes.go index a861adec..bb1fdae8 100644 --- a/api/routes.go +++ b/api/routes.go @@ -41,6 +41,8 @@ func AddRoutes(r *mux.Router) { r.Handle("/review/pool", authenticatedHandlerJSONPost(postReviewPool)).Methods("POST") review_task := resource.ReviewTask(r) r.Handle("/review-task", authenticatedHandlerJSON(review_task.List)).Methods("GET") + compliance := resource.Compliance(router) + r.HandleFunc("/rmo/compliance", handlerFormPost(compliance.Create)).Methods("POST") nuisance := resource.Nuisance(router) r.HandleFunc("/rmo/nuisance", handlerFormPost(nuisance.Create)).Methods("POST") water := resource.Water(router) diff --git a/db/dberrors/publicreport.client.bob.go b/db/dberrors/publicreport.client.bob.go new file mode 100644 index 00000000..a3372241 --- /dev/null +++ b/db/dberrors/publicreport.client.bob.go @@ -0,0 +1,17 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dberrors + +var PublicreportClientErrors = &publicreportClientErrors{ + ErrUniqueClientPkey: &UniqueConstraintError{ + schema: "publicreport", + table: "client", + columns: []string{"uuid"}, + s: "client_pkey", + }, +} + +type publicreportClientErrors struct { + ErrUniqueClientPkey *UniqueConstraintError +} diff --git a/db/dberrors/publicreport.compliance.bob.go b/db/dberrors/publicreport.compliance.bob.go new file mode 100644 index 00000000..77ddceb3 --- /dev/null +++ b/db/dberrors/publicreport.compliance.bob.go @@ -0,0 +1,17 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dberrors + +var PublicreportComplianceErrors = &publicreportComplianceErrors{ + ErrUniqueCompliancePkey: &UniqueConstraintError{ + schema: "publicreport", + table: "compliance", + columns: []string{"report_id"}, + s: "compliance_pkey", + }, +} + +type publicreportComplianceErrors struct { + ErrUniqueCompliancePkey *UniqueConstraintError +} diff --git a/db/dbinfo/publicreport.client.bob.go b/db/dbinfo/publicreport.client.bob.go new file mode 100644 index 00000000..aec23223 --- /dev/null +++ b/db/dbinfo/publicreport.client.bob.go @@ -0,0 +1,112 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dbinfo + +import "github.com/aarondl/opt/null" + +var PublicreportClients = Table[ + publicreportClientColumns, + publicreportClientIndexes, + publicreportClientForeignKeys, + publicreportClientUniques, + publicreportClientChecks, +]{ + Schema: "publicreport", + Name: "client", + Columns: publicreportClientColumns{ + Created: column{ + Name: "created", + DBType: "timestamp without time zone", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + UserAgent: column{ + Name: "user_agent", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + UUID: column{ + Name: "uuid", + DBType: "uuid", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + }, + Indexes: publicreportClientIndexes{ + ClientPkey: index{ + Type: "btree", + Name: "client_pkey", + Columns: []indexColumn{ + { + Name: "uuid", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: true, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, + }, + PrimaryKey: &constraint{ + Name: "client_pkey", + Columns: []string{"uuid"}, + Comment: "", + }, + + Comment: "", +} + +type publicreportClientColumns struct { + Created column + UserAgent column + UUID column +} + +func (c publicreportClientColumns) AsSlice() []column { + return []column{ + c.Created, c.UserAgent, c.UUID, + } +} + +type publicreportClientIndexes struct { + ClientPkey index +} + +func (i publicreportClientIndexes) AsSlice() []index { + return []index{ + i.ClientPkey, + } +} + +type publicreportClientForeignKeys struct{} + +func (f publicreportClientForeignKeys) AsSlice() []foreignKey { + return []foreignKey{} +} + +type publicreportClientUniques struct{} + +func (u publicreportClientUniques) AsSlice() []constraint { + return []constraint{} +} + +type publicreportClientChecks struct{} + +func (c publicreportClientChecks) AsSlice() []check { + return []check{} +} diff --git a/db/dbinfo/publicreport.compliance.bob.go b/db/dbinfo/publicreport.compliance.bob.go new file mode 100644 index 00000000..990a92ff --- /dev/null +++ b/db/dbinfo/publicreport.compliance.bob.go @@ -0,0 +1,187 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dbinfo + +import "github.com/aarondl/opt/null" + +var PublicreportCompliances = Table[ + publicreportComplianceColumns, + publicreportComplianceIndexes, + publicreportComplianceForeignKeys, + publicreportComplianceUniques, + publicreportComplianceChecks, +]{ + Schema: "publicreport", + Name: "compliance", + Columns: publicreportComplianceColumns{ + AccessInstructions: column{ + Name: "access_instructions", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + AvailabilityNotes: column{ + Name: "availability_notes", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Comments: column{ + Name: "comments", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + GateCode: column{ + Name: "gate_code", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + HasDog: column{ + Name: "has_dog", + DBType: "boolean", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + PermissionType: column{ + Name: "permission_type", + DBType: "public.permissionaccesstype", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ReportID: column{ + Name: "report_id", + DBType: "integer", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ReportPhoneCanText: column{ + Name: "report_phone_can_text", + DBType: "boolean", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + WantsScheduled: column{ + Name: "wants_scheduled", + DBType: "boolean", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + }, + Indexes: publicreportComplianceIndexes{ + CompliancePkey: index{ + Type: "btree", + Name: "compliance_pkey", + Columns: []indexColumn{ + { + Name: "report_id", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: true, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, + }, + PrimaryKey: &constraint{ + Name: "compliance_pkey", + Columns: []string{"report_id"}, + Comment: "", + }, + ForeignKeys: publicreportComplianceForeignKeys{ + PublicreportComplianceComplianceReportIDFkey: foreignKey{ + constraint: constraint{ + Name: "publicreport.compliance.compliance_report_id_fkey", + Columns: []string{"report_id"}, + Comment: "", + }, + ForeignTable: "publicreport.report", + ForeignColumns: []string{"id"}, + }, + }, + + Comment: "", +} + +type publicreportComplianceColumns struct { + AccessInstructions column + AvailabilityNotes column + Comments column + GateCode column + HasDog column + PermissionType column + ReportID column + ReportPhoneCanText column + WantsScheduled column +} + +func (c publicreportComplianceColumns) AsSlice() []column { + return []column{ + c.AccessInstructions, c.AvailabilityNotes, c.Comments, c.GateCode, c.HasDog, c.PermissionType, c.ReportID, c.ReportPhoneCanText, c.WantsScheduled, + } +} + +type publicreportComplianceIndexes struct { + CompliancePkey index +} + +func (i publicreportComplianceIndexes) AsSlice() []index { + return []index{ + i.CompliancePkey, + } +} + +type publicreportComplianceForeignKeys struct { + PublicreportComplianceComplianceReportIDFkey foreignKey +} + +func (f publicreportComplianceForeignKeys) AsSlice() []foreignKey { + return []foreignKey{ + f.PublicreportComplianceComplianceReportIDFkey, + } +} + +type publicreportComplianceUniques struct{} + +func (u publicreportComplianceUniques) AsSlice() []constraint { + return []constraint{} +} + +type publicreportComplianceChecks struct{} + +func (c publicreportComplianceChecks) AsSlice() []check { + return []check{} +} diff --git a/db/dbinfo/publicreport.report.bob.go b/db/dbinfo/publicreport.report.bob.go index b73e46eb..06aa22df 100644 --- a/db/dbinfo/publicreport.report.bob.go +++ b/db/dbinfo/publicreport.report.bob.go @@ -267,6 +267,15 @@ var PublicreportReports = Table[ Generated: false, AutoIncr: false, }, + ClientUUID: column{ + Name: "client_uuid", + DBType: "uuid", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, }, Indexes: publicreportReportIndexes{ ReportPkey: index{ @@ -319,6 +328,15 @@ var PublicreportReports = Table[ ForeignTable: "address", ForeignColumns: []string{"id"}, }, + PublicreportReportReportClientUUIDFkey: foreignKey{ + constraint: constraint{ + Name: "publicreport.report.report_client_uuid_fkey", + Columns: []string{"client_uuid"}, + Comment: "", + }, + ForeignTable: "publicreport.client", + ForeignColumns: []string{"uuid"}, + }, PublicreportReportReportOrganizationIDFkey: foreignKey{ constraint: constraint{ Name: "publicreport.report.report_organization_id_fkey", @@ -378,11 +396,12 @@ type publicreportReportColumns struct { LocationLatitude column LocationLongitude column AddressGid column + ClientUUID column } func (c publicreportReportColumns) AsSlice() []column { return []column{ - c.AddressRaw, c.AddressNumber, c.AddressStreet, c.AddressLocality, c.AddressRegion, c.AddressPostalCode, c.AddressCountry, c.AddressID, c.Created, c.Location, c.H3cell, c.ID, c.LatlngAccuracyType, c.LatlngAccuracyValue, c.MapZoom, c.OrganizationID, c.PublicID, c.ReporterName, c.ReporterEmail, c.ReporterPhone, c.ReporterContactConsent, c.ReportType, c.Reviewed, c.ReviewerID, c.Status, c.LocationLatitude, c.LocationLongitude, c.AddressGid, + c.AddressRaw, c.AddressNumber, c.AddressStreet, c.AddressLocality, c.AddressRegion, c.AddressPostalCode, c.AddressCountry, c.AddressID, c.Created, c.Location, c.H3cell, c.ID, c.LatlngAccuracyType, c.LatlngAccuracyValue, c.MapZoom, c.OrganizationID, c.PublicID, c.ReporterName, c.ReporterEmail, c.ReporterPhone, c.ReporterContactConsent, c.ReportType, c.Reviewed, c.ReviewerID, c.Status, c.LocationLatitude, c.LocationLongitude, c.AddressGid, c.ClientUUID, } } @@ -399,13 +418,14 @@ func (i publicreportReportIndexes) AsSlice() []index { type publicreportReportForeignKeys struct { PublicreportReportReportAddressIDFkey foreignKey + PublicreportReportReportClientUUIDFkey foreignKey PublicreportReportReportOrganizationIDFkey foreignKey PublicreportReportReportReviewerIDFkey foreignKey } func (f publicreportReportForeignKeys) AsSlice() []foreignKey { return []foreignKey{ - f.PublicreportReportReportAddressIDFkey, f.PublicreportReportReportOrganizationIDFkey, f.PublicreportReportReportReviewerIDFkey, + f.PublicreportReportReportAddressIDFkey, f.PublicreportReportReportClientUUIDFkey, f.PublicreportReportReportOrganizationIDFkey, f.PublicreportReportReportReviewerIDFkey, } } diff --git a/db/enums/enums.bob.go b/db/enums/enums.bob.go index 7bf7b211..eb2085a4 100644 --- a/db/enums/enums.bob.go +++ b/db/enums/enums.bob.go @@ -1614,6 +1614,85 @@ func (e *Notificationtype) Scan(value any) error { return nil } +// Enum values for Permissionaccesstype +const ( + PermissionaccesstypeDenied Permissionaccesstype = "denied" + PermissionaccesstypeGranted Permissionaccesstype = "granted" + PermissionaccesstypeUnselected Permissionaccesstype = "unselected" + PermissionaccesstypeWithOwner Permissionaccesstype = "with-owner" +) + +func AllPermissionaccesstype() []Permissionaccesstype { + return []Permissionaccesstype{ + PermissionaccesstypeDenied, + PermissionaccesstypeGranted, + PermissionaccesstypeUnselected, + PermissionaccesstypeWithOwner, + } +} + +type Permissionaccesstype string + +func (e Permissionaccesstype) String() string { + return string(e) +} + +func (e Permissionaccesstype) Valid() bool { + switch e { + case PermissionaccesstypeDenied, + PermissionaccesstypeGranted, + PermissionaccesstypeUnselected, + PermissionaccesstypeWithOwner: + return true + default: + return false + } +} + +// useful when testing in other packages +func (e Permissionaccesstype) All() []Permissionaccesstype { + return AllPermissionaccesstype() +} + +func (e Permissionaccesstype) MarshalText() ([]byte, error) { + return []byte(e), nil +} + +func (e *Permissionaccesstype) UnmarshalText(text []byte) error { + return e.Scan(text) +} + +func (e Permissionaccesstype) MarshalBinary() ([]byte, error) { + return []byte(e), nil +} + +func (e *Permissionaccesstype) UnmarshalBinary(data []byte) error { + return e.Scan(data) +} + +func (e Permissionaccesstype) Value() (driver.Value, error) { + return string(e), nil +} + +func (e *Permissionaccesstype) Scan(value any) error { + switch x := value.(type) { + case string: + *e = Permissionaccesstype(x) + case []byte: + *e = Permissionaccesstype(x) + case nil: + return fmt.Errorf("cannot nil into Permissionaccesstype") + default: + return fmt.Errorf("cannot scan type %T: %v", value, value) + } + + if !e.Valid() { + return fmt.Errorf("invalid Permissionaccesstype value: %s", *e) + } + + return nil +} + // Enum values for Poolconditiontype const ( PoolconditiontypeBlue Poolconditiontype = "blue" diff --git a/db/migrations/00128_publicreport_compliance.sql b/db/migrations/00128_publicreport_compliance.sql new file mode 100644 index 00000000..8cdc4621 --- /dev/null +++ b/db/migrations/00128_publicreport_compliance.sql @@ -0,0 +1,31 @@ +-- +goose Up +CREATE TYPE PermissionAccessType AS ENUM ( + 'denied', + 'granted', + 'unselected', + 'with-owner' +); +CREATE TABLE publicreport.compliance ( + access_instructions TEXT NOT NULL, + availability_notes TEXT NOT NULL, + comments TEXT NOT NULL, + gate_code TEXT NOT NULL, + has_dog BOOLEAN, + permission_type PermissionAccessType NOT NULL, + report_id INTEGER REFERENCES publicreport.report(id), + report_phone_can_text BOOLEAN, + wants_scheduled BOOLEAN, + PRIMARY KEY(report_id) +); +CREATE TABLE publicreport.client ( + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + user_agent TEXT NOT NULL, + uuid UUID NOT NULL, + PRIMARY KEY(uuid) +); +ALTER TABLE publicreport.report ADD COLUMN client_uuid UUID REFERENCES publicreport.client(uuid); +-- +goose Down +ALTER TABLE publicreport.report DROP COLUMN client_uuid; +DROP TABLE publicreport.client; +DROP TABLE publicreport.compliance; +DROP TYPE PermissionAccessType; diff --git a/db/models/bob_loaders.bob.go b/db/models/bob_loaders.bob.go index 16317dfd..c06b290f 100644 --- a/db/models/bob_loaders.bob.go +++ b/db/models/bob_loaders.bob.go @@ -86,6 +86,8 @@ type preloaders struct { Notification notificationPreloader Organization organizationPreloader Parcel parcelPreloader + PublicreportClient publicreportClientPreloader + PublicreportCompliance publicreportCompliancePreloader PublicreportImage publicreportImagePreloader PublicreportImageExif publicreportImageExifPreloader PublicreportNotifyEmail publicreportNotifyEmailPreloader @@ -186,6 +188,8 @@ func getPreloaders() preloaders { Notification: buildNotificationPreloader(), Organization: buildOrganizationPreloader(), Parcel: buildParcelPreloader(), + PublicreportClient: buildPublicreportClientPreloader(), + PublicreportCompliance: buildPublicreportCompliancePreloader(), PublicreportImage: buildPublicreportImagePreloader(), PublicreportImageExif: buildPublicreportImageExifPreloader(), PublicreportNotifyEmail: buildPublicreportNotifyEmailPreloader(), @@ -292,6 +296,8 @@ type thenLoaders[Q orm.Loadable] struct { Notification notificationThenLoader[Q] Organization organizationThenLoader[Q] Parcel parcelThenLoader[Q] + PublicreportClient publicreportClientThenLoader[Q] + PublicreportCompliance publicreportComplianceThenLoader[Q] PublicreportImage publicreportImageThenLoader[Q] PublicreportImageExif publicreportImageExifThenLoader[Q] PublicreportNotifyEmail publicreportNotifyEmailThenLoader[Q] @@ -392,6 +398,8 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] { Notification: buildNotificationThenLoader[Q](), Organization: buildOrganizationThenLoader[Q](), Parcel: buildParcelThenLoader[Q](), + PublicreportClient: buildPublicreportClientThenLoader[Q](), + PublicreportCompliance: buildPublicreportComplianceThenLoader[Q](), PublicreportImage: buildPublicreportImageThenLoader[Q](), PublicreportImageExif: buildPublicreportImageExifThenLoader[Q](), PublicreportNotifyEmail: buildPublicreportNotifyEmailThenLoader[Q](), diff --git a/db/models/bob_where.bob.go b/db/models/bob_where.bob.go index bd41c6c1..2aec75f9 100644 --- a/db/models/bob_where.bob.go +++ b/db/models/bob_where.bob.go @@ -90,6 +90,8 @@ func Where[Q psql.Filterable]() struct { Notifications notificationWhere[Q] Organizations organizationWhere[Q] Parcels parcelWhere[Q] + PublicreportClients publicreportClientWhere[Q] + PublicreportCompliances publicreportComplianceWhere[Q] PublicreportImages publicreportImageWhere[Q] PublicreportImageExifs publicreportImageExifWhere[Q] PublicreportNotifyEmails publicreportNotifyEmailWhere[Q] @@ -198,6 +200,8 @@ func Where[Q psql.Filterable]() struct { Notifications notificationWhere[Q] Organizations organizationWhere[Q] Parcels parcelWhere[Q] + PublicreportClients publicreportClientWhere[Q] + PublicreportCompliances publicreportComplianceWhere[Q] PublicreportImages publicreportImageWhere[Q] PublicreportImageExifs publicreportImageExifWhere[Q] PublicreportNotifyEmails publicreportNotifyEmailWhere[Q] @@ -305,6 +309,8 @@ func Where[Q psql.Filterable]() struct { Notifications: buildNotificationWhere[Q](Notifications.Columns), Organizations: buildOrganizationWhere[Q](Organizations.Columns), Parcels: buildParcelWhere[Q](Parcels.Columns), + PublicreportClients: buildPublicreportClientWhere[Q](PublicreportClients.Columns), + PublicreportCompliances: buildPublicreportComplianceWhere[Q](PublicreportCompliances.Columns), PublicreportImages: buildPublicreportImageWhere[Q](PublicreportImages.Columns), PublicreportImageExifs: buildPublicreportImageExifWhere[Q](PublicreportImageExifs.Columns), PublicreportNotifyEmails: buildPublicreportNotifyEmailWhere[Q](PublicreportNotifyEmails.Columns), diff --git a/db/models/publicreport.client.bob.go b/db/models/publicreport.client.bob.go new file mode 100644 index 00000000..6450bdf2 --- /dev/null +++ b/db/models/publicreport.client.bob.go @@ -0,0 +1,618 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "fmt" + "io" + "time" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/dialect" + "github.com/Gleipnir-Technology/bob/dialect/psql/dm" + "github.com/Gleipnir-Technology/bob/dialect/psql/sm" + "github.com/Gleipnir-Technology/bob/dialect/psql/um" + "github.com/Gleipnir-Technology/bob/expr" + "github.com/Gleipnir-Technology/bob/orm" + "github.com/Gleipnir-Technology/bob/types/pgtypes" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/google/uuid" +) + +// PublicreportClient is an object representing the database table. +type PublicreportClient struct { + Created time.Time `db:"created" ` + UserAgent string `db:"user_agent" ` + UUID uuid.UUID `db:"uuid,pk" ` + + R publicreportClientR `db:"-" ` +} + +// PublicreportClientSlice is an alias for a slice of pointers to PublicreportClient. +// This should almost always be used instead of []*PublicreportClient. +type PublicreportClientSlice []*PublicreportClient + +// PublicreportClients contains methods to work with the client table +var PublicreportClients = psql.NewTablex[*PublicreportClient, PublicreportClientSlice, *PublicreportClientSetter]("publicreport", "client", buildPublicreportClientColumns("publicreport.client")) + +// PublicreportClientsQuery is a query on the client table +type PublicreportClientsQuery = *psql.ViewQuery[*PublicreportClient, PublicreportClientSlice] + +// publicreportClientR is where relationships are stored. +type publicreportClientR struct { + Reports PublicreportReportSlice // publicreport.report.report_client_uuid_fkey +} + +func buildPublicreportClientColumns(alias string) publicreportClientColumns { + return publicreportClientColumns{ + ColumnsExpr: expr.NewColumnsExpr( + "created", "user_agent", "uuid", + ).WithParent("publicreport.client"), + tableAlias: alias, + Created: psql.Quote(alias, "created"), + UserAgent: psql.Quote(alias, "user_agent"), + UUID: psql.Quote(alias, "uuid"), + } +} + +type publicreportClientColumns struct { + expr.ColumnsExpr + tableAlias string + Created psql.Expression + UserAgent psql.Expression + UUID psql.Expression +} + +func (c publicreportClientColumns) Alias() string { + return c.tableAlias +} + +func (publicreportClientColumns) AliasedAs(alias string) publicreportClientColumns { + return buildPublicreportClientColumns(alias) +} + +// PublicreportClientSetter is used for insert/upsert/update operations +// All values are optional, and do not have to be set +// Generated columns are not included +type PublicreportClientSetter struct { + Created omit.Val[time.Time] `db:"created" ` + UserAgent omit.Val[string] `db:"user_agent" ` + UUID omit.Val[uuid.UUID] `db:"uuid,pk" ` +} + +func (s PublicreportClientSetter) SetColumns() []string { + vals := make([]string, 0, 3) + if s.Created.IsValue() { + vals = append(vals, "created") + } + if s.UserAgent.IsValue() { + vals = append(vals, "user_agent") + } + if s.UUID.IsValue() { + vals = append(vals, "uuid") + } + return vals +} + +func (s PublicreportClientSetter) Overwrite(t *PublicreportClient) { + if s.Created.IsValue() { + t.Created = s.Created.MustGet() + } + if s.UserAgent.IsValue() { + t.UserAgent = s.UserAgent.MustGet() + } + if s.UUID.IsValue() { + t.UUID = s.UUID.MustGet() + } +} + +func (s *PublicreportClientSetter) Apply(q *dialect.InsertQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportClients.BeforeInsertHooks.RunHooks(ctx, exec, s) + }) + + q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + vals := make([]bob.Expression, 3) + if s.Created.IsValue() { + vals[0] = psql.Arg(s.Created.MustGet()) + } else { + vals[0] = psql.Raw("DEFAULT") + } + + if s.UserAgent.IsValue() { + vals[1] = psql.Arg(s.UserAgent.MustGet()) + } else { + vals[1] = psql.Raw("DEFAULT") + } + + if s.UUID.IsValue() { + vals[2] = psql.Arg(s.UUID.MustGet()) + } else { + vals[2] = psql.Raw("DEFAULT") + } + + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") + })) +} + +func (s PublicreportClientSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return um.Set(s.Expressions()...) +} + +func (s PublicreportClientSetter) Expressions(prefix ...string) []bob.Expression { + exprs := make([]bob.Expression, 0, 3) + + if s.Created.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "created")...), + psql.Arg(s.Created), + }}) + } + + if s.UserAgent.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "user_agent")...), + psql.Arg(s.UserAgent), + }}) + } + + if s.UUID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "uuid")...), + psql.Arg(s.UUID), + }}) + } + + return exprs +} + +// FindPublicreportClient retrieves a single record by primary key +// If cols is empty Find will return all columns. +func FindPublicreportClient(ctx context.Context, exec bob.Executor, UUIDPK uuid.UUID, cols ...string) (*PublicreportClient, error) { + if len(cols) == 0 { + return PublicreportClients.Query( + sm.Where(PublicreportClients.Columns.UUID.EQ(psql.Arg(UUIDPK))), + ).One(ctx, exec) + } + + return PublicreportClients.Query( + sm.Where(PublicreportClients.Columns.UUID.EQ(psql.Arg(UUIDPK))), + sm.Columns(PublicreportClients.Columns.Only(cols...)), + ).One(ctx, exec) +} + +// PublicreportClientExists checks the presence of a single record by primary key +func PublicreportClientExists(ctx context.Context, exec bob.Executor, UUIDPK uuid.UUID) (bool, error) { + return PublicreportClients.Query( + sm.Where(PublicreportClients.Columns.UUID.EQ(psql.Arg(UUIDPK))), + ).Exists(ctx, exec) +} + +// AfterQueryHook is called after PublicreportClient is retrieved from the database +func (o *PublicreportClient) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = PublicreportClients.AfterSelectHooks.RunHooks(ctx, exec, PublicreportClientSlice{o}) + case bob.QueryTypeInsert: + ctx, err = PublicreportClients.AfterInsertHooks.RunHooks(ctx, exec, PublicreportClientSlice{o}) + case bob.QueryTypeUpdate: + ctx, err = PublicreportClients.AfterUpdateHooks.RunHooks(ctx, exec, PublicreportClientSlice{o}) + case bob.QueryTypeDelete: + ctx, err = PublicreportClients.AfterDeleteHooks.RunHooks(ctx, exec, PublicreportClientSlice{o}) + } + + return err +} + +// primaryKeyVals returns the primary key values of the PublicreportClient +func (o *PublicreportClient) primaryKeyVals() bob.Expression { + return psql.Arg(o.UUID) +} + +func (o *PublicreportClient) pkEQ() dialect.Expression { + return psql.Quote("publicreport.client", "uuid").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return o.primaryKeyVals().WriteSQL(ctx, w, d, start) + })) +} + +// Update uses an executor to update the PublicreportClient +func (o *PublicreportClient) Update(ctx context.Context, exec bob.Executor, s *PublicreportClientSetter) error { + v, err := PublicreportClients.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) + if err != nil { + return err + } + + o.R = v.R + *o = *v + + return nil +} + +// Delete deletes a single PublicreportClient record with an executor +func (o *PublicreportClient) Delete(ctx context.Context, exec bob.Executor) error { + _, err := PublicreportClients.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) + return err +} + +// Reload refreshes the PublicreportClient using the executor +func (o *PublicreportClient) Reload(ctx context.Context, exec bob.Executor) error { + o2, err := PublicreportClients.Query( + sm.Where(PublicreportClients.Columns.UUID.EQ(psql.Arg(o.UUID))), + ).One(ctx, exec) + if err != nil { + return err + } + o2.R = o.R + *o = *o2 + + return nil +} + +// AfterQueryHook is called after PublicreportClientSlice is retrieved from the database +func (o PublicreportClientSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = PublicreportClients.AfterSelectHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeInsert: + ctx, err = PublicreportClients.AfterInsertHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeUpdate: + ctx, err = PublicreportClients.AfterUpdateHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeDelete: + ctx, err = PublicreportClients.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err +} + +func (o PublicreportClientSlice) pkIN() dialect.Expression { + if len(o) == 0 { + return psql.Raw("NULL") + } + + return psql.Quote("publicreport.client", "uuid").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + pkPairs := make([]bob.Expression, len(o)) + for i, row := range o { + pkPairs[i] = row.primaryKeyVals() + } + return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") + })) +} + +// copyMatchingRows finds models in the given slice that have the same primary key +// then it first copies the existing relationships from the old model to the new model +// and then replaces the old model in the slice with the new model +func (o PublicreportClientSlice) copyMatchingRows(from ...*PublicreportClient) { + for i, old := range o { + for _, new := range from { + if new.UUID != old.UUID { + continue + } + new.R = old.R + o[i] = new + break + } + } +} + +// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" +func (o PublicreportClientSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportClients.BeforeUpdateHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *PublicreportClient: + o.copyMatchingRows(retrieved) + case []*PublicreportClient: + o.copyMatchingRows(retrieved...) + case PublicreportClientSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a PublicreportClient or a slice of PublicreportClient + // then run the AfterUpdateHooks on the slice + _, err = PublicreportClients.AfterUpdateHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" +func (o PublicreportClientSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { + return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportClients.BeforeDeleteHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *PublicreportClient: + o.copyMatchingRows(retrieved) + case []*PublicreportClient: + o.copyMatchingRows(retrieved...) + case PublicreportClientSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a PublicreportClient or a slice of PublicreportClient + // then run the AfterDeleteHooks on the slice + _, err = PublicreportClients.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +func (o PublicreportClientSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals PublicreportClientSetter) error { + if len(o) == 0 { + return nil + } + + _, err := PublicreportClients.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) + return err +} + +func (o PublicreportClientSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + _, err := PublicreportClients.Delete(o.DeleteMod()).Exec(ctx, exec) + return err +} + +func (o PublicreportClientSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + o2, err := PublicreportClients.Query(sm.Where(o.pkIN())).All(ctx, exec) + if err != nil { + return err + } + + o.copyMatchingRows(o2...) + + return nil +} + +// Reports starts a query for related objects on publicreport.report +func (o *PublicreportClient) Reports(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportReportsQuery { + return PublicreportReports.Query(append(mods, + sm.Where(PublicreportReports.Columns.ClientUUID.EQ(psql.Arg(o.UUID))), + )...) +} + +func (os PublicreportClientSlice) Reports(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportReportsQuery { + pkUUID := make(pgtypes.Array[uuid.UUID], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkUUID = append(pkUUID, o.UUID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkUUID), "uuid[]")), + )) + + return PublicreportReports.Query(append(mods, + sm.Where(psql.Group(PublicreportReports.Columns.ClientUUID).OP("IN", PKArgExpr)), + )...) +} + +func insertPublicreportClientReports0(ctx context.Context, exec bob.Executor, publicreportReports1 []*PublicreportReportSetter, publicreportClient0 *PublicreportClient) (PublicreportReportSlice, error) { + for i := range publicreportReports1 { + publicreportReports1[i].ClientUUID = omitnull.From(publicreportClient0.UUID) + } + + ret, err := PublicreportReports.Insert(bob.ToMods(publicreportReports1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertPublicreportClientReports0: %w", err) + } + + return ret, nil +} + +func attachPublicreportClientReports0(ctx context.Context, exec bob.Executor, count int, publicreportReports1 PublicreportReportSlice, publicreportClient0 *PublicreportClient) (PublicreportReportSlice, error) { + setter := &PublicreportReportSetter{ + ClientUUID: omitnull.From(publicreportClient0.UUID), + } + + err := publicreportReports1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachPublicreportClientReports0: %w", err) + } + + return publicreportReports1, nil +} + +func (publicreportClient0 *PublicreportClient) InsertReports(ctx context.Context, exec bob.Executor, related ...*PublicreportReportSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + publicreportReports1, err := insertPublicreportClientReports0(ctx, exec, related, publicreportClient0) + if err != nil { + return err + } + + publicreportClient0.R.Reports = append(publicreportClient0.R.Reports, publicreportReports1...) + + for _, rel := range publicreportReports1 { + rel.R.Client = publicreportClient0 + } + return nil +} + +func (publicreportClient0 *PublicreportClient) AttachReports(ctx context.Context, exec bob.Executor, related ...*PublicreportReport) error { + if len(related) == 0 { + return nil + } + + var err error + publicreportReports1 := PublicreportReportSlice(related) + + _, err = attachPublicreportClientReports0(ctx, exec, len(related), publicreportReports1, publicreportClient0) + if err != nil { + return err + } + + publicreportClient0.R.Reports = append(publicreportClient0.R.Reports, publicreportReports1...) + + for _, rel := range related { + rel.R.Client = publicreportClient0 + } + + return nil +} + +type publicreportClientWhere[Q psql.Filterable] struct { + Created psql.WhereMod[Q, time.Time] + UserAgent psql.WhereMod[Q, string] + UUID psql.WhereMod[Q, uuid.UUID] +} + +func (publicreportClientWhere[Q]) AliasedAs(alias string) publicreportClientWhere[Q] { + return buildPublicreportClientWhere[Q](buildPublicreportClientColumns(alias)) +} + +func buildPublicreportClientWhere[Q psql.Filterable](cols publicreportClientColumns) publicreportClientWhere[Q] { + return publicreportClientWhere[Q]{ + Created: psql.Where[Q, time.Time](cols.Created), + UserAgent: psql.Where[Q, string](cols.UserAgent), + UUID: psql.Where[Q, uuid.UUID](cols.UUID), + } +} + +func (o *PublicreportClient) Preload(name string, retrieved any) error { + if o == nil { + return nil + } + + switch name { + case "Reports": + rels, ok := retrieved.(PublicreportReportSlice) + if !ok { + return fmt.Errorf("publicreportClient cannot load %T as %q", retrieved, name) + } + + o.R.Reports = rels + + for _, rel := range rels { + if rel != nil { + rel.R.Client = o + } + } + return nil + default: + return fmt.Errorf("publicreportClient has no relationship %q", name) + } +} + +type publicreportClientPreloader struct{} + +func buildPublicreportClientPreloader() publicreportClientPreloader { + return publicreportClientPreloader{} +} + +type publicreportClientThenLoader[Q orm.Loadable] struct { + Reports func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildPublicreportClientThenLoader[Q orm.Loadable]() publicreportClientThenLoader[Q] { + type ReportsLoadInterface interface { + LoadReports(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return publicreportClientThenLoader[Q]{ + Reports: thenLoadBuilder[Q]( + "Reports", + func(ctx context.Context, exec bob.Executor, retrieved ReportsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadReports(ctx, exec, mods...) + }, + ), + } +} + +// LoadReports loads the publicreportClient's Reports into the .R struct +func (o *PublicreportClient) LoadReports(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Reports = nil + + related, err := o.Reports(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.Client = o + } + + o.R.Reports = related + return nil +} + +// LoadReports loads the publicreportClient's Reports into the .R struct +func (os PublicreportClientSlice) LoadReports(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + publicreportReports, err := os.Reports(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.Reports = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range publicreportReports { + + if !rel.ClientUUID.IsValue() { + continue + } + if !(rel.ClientUUID.IsValue() && o.UUID == rel.ClientUUID.MustGet()) { + continue + } + + rel.R.Client = o + + o.R.Reports = append(o.R.Reports, rel) + } + } + + return nil +} diff --git a/db/models/publicreport.compliance.bob.go b/db/models/publicreport.compliance.bob.go new file mode 100644 index 00000000..35a8946a --- /dev/null +++ b/db/models/publicreport.compliance.bob.go @@ -0,0 +1,750 @@ +// Code generated by BobGen psql v0.42.5. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "fmt" + "io" + + "github.com/Gleipnir-Technology/bob" + "github.com/Gleipnir-Technology/bob/dialect/psql" + "github.com/Gleipnir-Technology/bob/dialect/psql/dialect" + "github.com/Gleipnir-Technology/bob/dialect/psql/dm" + "github.com/Gleipnir-Technology/bob/dialect/psql/sm" + "github.com/Gleipnir-Technology/bob/dialect/psql/um" + "github.com/Gleipnir-Technology/bob/expr" + "github.com/Gleipnir-Technology/bob/orm" + "github.com/Gleipnir-Technology/bob/types/pgtypes" + enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/aarondl/opt/null" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" +) + +// PublicreportCompliance is an object representing the database table. +type PublicreportCompliance struct { + AccessInstructions string `db:"access_instructions" ` + AvailabilityNotes string `db:"availability_notes" ` + Comments string `db:"comments" ` + GateCode string `db:"gate_code" ` + HasDog null.Val[bool] `db:"has_dog" ` + PermissionType enums.Permissionaccesstype `db:"permission_type" ` + ReportID int32 `db:"report_id,pk" ` + ReportPhoneCanText null.Val[bool] `db:"report_phone_can_text" ` + WantsScheduled null.Val[bool] `db:"wants_scheduled" ` + + R publicreportComplianceR `db:"-" ` +} + +// PublicreportComplianceSlice is an alias for a slice of pointers to PublicreportCompliance. +// This should almost always be used instead of []*PublicreportCompliance. +type PublicreportComplianceSlice []*PublicreportCompliance + +// PublicreportCompliances contains methods to work with the compliance table +var PublicreportCompliances = psql.NewTablex[*PublicreportCompliance, PublicreportComplianceSlice, *PublicreportComplianceSetter]("publicreport", "compliance", buildPublicreportComplianceColumns("publicreport.compliance")) + +// PublicreportCompliancesQuery is a query on the compliance table +type PublicreportCompliancesQuery = *psql.ViewQuery[*PublicreportCompliance, PublicreportComplianceSlice] + +// publicreportComplianceR is where relationships are stored. +type publicreportComplianceR struct { + Report *PublicreportReport // publicreport.compliance.compliance_report_id_fkey +} + +func buildPublicreportComplianceColumns(alias string) publicreportComplianceColumns { + return publicreportComplianceColumns{ + ColumnsExpr: expr.NewColumnsExpr( + "access_instructions", "availability_notes", "comments", "gate_code", "has_dog", "permission_type", "report_id", "report_phone_can_text", "wants_scheduled", + ).WithParent("publicreport.compliance"), + tableAlias: alias, + AccessInstructions: psql.Quote(alias, "access_instructions"), + AvailabilityNotes: psql.Quote(alias, "availability_notes"), + Comments: psql.Quote(alias, "comments"), + GateCode: psql.Quote(alias, "gate_code"), + HasDog: psql.Quote(alias, "has_dog"), + PermissionType: psql.Quote(alias, "permission_type"), + ReportID: psql.Quote(alias, "report_id"), + ReportPhoneCanText: psql.Quote(alias, "report_phone_can_text"), + WantsScheduled: psql.Quote(alias, "wants_scheduled"), + } +} + +type publicreportComplianceColumns struct { + expr.ColumnsExpr + tableAlias string + AccessInstructions psql.Expression + AvailabilityNotes psql.Expression + Comments psql.Expression + GateCode psql.Expression + HasDog psql.Expression + PermissionType psql.Expression + ReportID psql.Expression + ReportPhoneCanText psql.Expression + WantsScheduled psql.Expression +} + +func (c publicreportComplianceColumns) Alias() string { + return c.tableAlias +} + +func (publicreportComplianceColumns) AliasedAs(alias string) publicreportComplianceColumns { + return buildPublicreportComplianceColumns(alias) +} + +// PublicreportComplianceSetter is used for insert/upsert/update operations +// All values are optional, and do not have to be set +// Generated columns are not included +type PublicreportComplianceSetter struct { + AccessInstructions omit.Val[string] `db:"access_instructions" ` + AvailabilityNotes omit.Val[string] `db:"availability_notes" ` + Comments omit.Val[string] `db:"comments" ` + GateCode omit.Val[string] `db:"gate_code" ` + HasDog omitnull.Val[bool] `db:"has_dog" ` + PermissionType omit.Val[enums.Permissionaccesstype] `db:"permission_type" ` + ReportID omit.Val[int32] `db:"report_id,pk" ` + ReportPhoneCanText omitnull.Val[bool] `db:"report_phone_can_text" ` + WantsScheduled omitnull.Val[bool] `db:"wants_scheduled" ` +} + +func (s PublicreportComplianceSetter) SetColumns() []string { + vals := make([]string, 0, 9) + if s.AccessInstructions.IsValue() { + vals = append(vals, "access_instructions") + } + if s.AvailabilityNotes.IsValue() { + vals = append(vals, "availability_notes") + } + if s.Comments.IsValue() { + vals = append(vals, "comments") + } + if s.GateCode.IsValue() { + vals = append(vals, "gate_code") + } + if !s.HasDog.IsUnset() { + vals = append(vals, "has_dog") + } + if s.PermissionType.IsValue() { + vals = append(vals, "permission_type") + } + if s.ReportID.IsValue() { + vals = append(vals, "report_id") + } + if !s.ReportPhoneCanText.IsUnset() { + vals = append(vals, "report_phone_can_text") + } + if !s.WantsScheduled.IsUnset() { + vals = append(vals, "wants_scheduled") + } + return vals +} + +func (s PublicreportComplianceSetter) Overwrite(t *PublicreportCompliance) { + if s.AccessInstructions.IsValue() { + t.AccessInstructions = s.AccessInstructions.MustGet() + } + if s.AvailabilityNotes.IsValue() { + t.AvailabilityNotes = s.AvailabilityNotes.MustGet() + } + if s.Comments.IsValue() { + t.Comments = s.Comments.MustGet() + } + if s.GateCode.IsValue() { + t.GateCode = s.GateCode.MustGet() + } + if !s.HasDog.IsUnset() { + t.HasDog = s.HasDog.MustGetNull() + } + if s.PermissionType.IsValue() { + t.PermissionType = s.PermissionType.MustGet() + } + if s.ReportID.IsValue() { + t.ReportID = s.ReportID.MustGet() + } + if !s.ReportPhoneCanText.IsUnset() { + t.ReportPhoneCanText = s.ReportPhoneCanText.MustGetNull() + } + if !s.WantsScheduled.IsUnset() { + t.WantsScheduled = s.WantsScheduled.MustGetNull() + } +} + +func (s *PublicreportComplianceSetter) Apply(q *dialect.InsertQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportCompliances.BeforeInsertHooks.RunHooks(ctx, exec, s) + }) + + q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + vals := make([]bob.Expression, 9) + if s.AccessInstructions.IsValue() { + vals[0] = psql.Arg(s.AccessInstructions.MustGet()) + } else { + vals[0] = psql.Raw("DEFAULT") + } + + if s.AvailabilityNotes.IsValue() { + vals[1] = psql.Arg(s.AvailabilityNotes.MustGet()) + } else { + vals[1] = psql.Raw("DEFAULT") + } + + if s.Comments.IsValue() { + vals[2] = psql.Arg(s.Comments.MustGet()) + } else { + vals[2] = psql.Raw("DEFAULT") + } + + if s.GateCode.IsValue() { + vals[3] = psql.Arg(s.GateCode.MustGet()) + } else { + vals[3] = psql.Raw("DEFAULT") + } + + if !s.HasDog.IsUnset() { + vals[4] = psql.Arg(s.HasDog.MustGetNull()) + } else { + vals[4] = psql.Raw("DEFAULT") + } + + if s.PermissionType.IsValue() { + vals[5] = psql.Arg(s.PermissionType.MustGet()) + } else { + vals[5] = psql.Raw("DEFAULT") + } + + if s.ReportID.IsValue() { + vals[6] = psql.Arg(s.ReportID.MustGet()) + } else { + vals[6] = psql.Raw("DEFAULT") + } + + if !s.ReportPhoneCanText.IsUnset() { + vals[7] = psql.Arg(s.ReportPhoneCanText.MustGetNull()) + } else { + vals[7] = psql.Raw("DEFAULT") + } + + if !s.WantsScheduled.IsUnset() { + vals[8] = psql.Arg(s.WantsScheduled.MustGetNull()) + } else { + vals[8] = psql.Raw("DEFAULT") + } + + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") + })) +} + +func (s PublicreportComplianceSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return um.Set(s.Expressions()...) +} + +func (s PublicreportComplianceSetter) Expressions(prefix ...string) []bob.Expression { + exprs := make([]bob.Expression, 0, 9) + + if s.AccessInstructions.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "access_instructions")...), + psql.Arg(s.AccessInstructions), + }}) + } + + if s.AvailabilityNotes.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "availability_notes")...), + psql.Arg(s.AvailabilityNotes), + }}) + } + + if s.Comments.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "comments")...), + psql.Arg(s.Comments), + }}) + } + + if s.GateCode.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "gate_code")...), + psql.Arg(s.GateCode), + }}) + } + + if !s.HasDog.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "has_dog")...), + psql.Arg(s.HasDog), + }}) + } + + if s.PermissionType.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "permission_type")...), + psql.Arg(s.PermissionType), + }}) + } + + if s.ReportID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "report_id")...), + psql.Arg(s.ReportID), + }}) + } + + if !s.ReportPhoneCanText.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "report_phone_can_text")...), + psql.Arg(s.ReportPhoneCanText), + }}) + } + + if !s.WantsScheduled.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "wants_scheduled")...), + psql.Arg(s.WantsScheduled), + }}) + } + + return exprs +} + +// FindPublicreportCompliance retrieves a single record by primary key +// If cols is empty Find will return all columns. +func FindPublicreportCompliance(ctx context.Context, exec bob.Executor, ReportIDPK int32, cols ...string) (*PublicreportCompliance, error) { + if len(cols) == 0 { + return PublicreportCompliances.Query( + sm.Where(PublicreportCompliances.Columns.ReportID.EQ(psql.Arg(ReportIDPK))), + ).One(ctx, exec) + } + + return PublicreportCompliances.Query( + sm.Where(PublicreportCompliances.Columns.ReportID.EQ(psql.Arg(ReportIDPK))), + sm.Columns(PublicreportCompliances.Columns.Only(cols...)), + ).One(ctx, exec) +} + +// PublicreportComplianceExists checks the presence of a single record by primary key +func PublicreportComplianceExists(ctx context.Context, exec bob.Executor, ReportIDPK int32) (bool, error) { + return PublicreportCompliances.Query( + sm.Where(PublicreportCompliances.Columns.ReportID.EQ(psql.Arg(ReportIDPK))), + ).Exists(ctx, exec) +} + +// AfterQueryHook is called after PublicreportCompliance is retrieved from the database +func (o *PublicreportCompliance) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = PublicreportCompliances.AfterSelectHooks.RunHooks(ctx, exec, PublicreportComplianceSlice{o}) + case bob.QueryTypeInsert: + ctx, err = PublicreportCompliances.AfterInsertHooks.RunHooks(ctx, exec, PublicreportComplianceSlice{o}) + case bob.QueryTypeUpdate: + ctx, err = PublicreportCompliances.AfterUpdateHooks.RunHooks(ctx, exec, PublicreportComplianceSlice{o}) + case bob.QueryTypeDelete: + ctx, err = PublicreportCompliances.AfterDeleteHooks.RunHooks(ctx, exec, PublicreportComplianceSlice{o}) + } + + return err +} + +// primaryKeyVals returns the primary key values of the PublicreportCompliance +func (o *PublicreportCompliance) primaryKeyVals() bob.Expression { + return psql.Arg(o.ReportID) +} + +func (o *PublicreportCompliance) pkEQ() dialect.Expression { + return psql.Quote("publicreport.compliance", "report_id").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return o.primaryKeyVals().WriteSQL(ctx, w, d, start) + })) +} + +// Update uses an executor to update the PublicreportCompliance +func (o *PublicreportCompliance) Update(ctx context.Context, exec bob.Executor, s *PublicreportComplianceSetter) error { + v, err := PublicreportCompliances.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) + if err != nil { + return err + } + + o.R = v.R + *o = *v + + return nil +} + +// Delete deletes a single PublicreportCompliance record with an executor +func (o *PublicreportCompliance) Delete(ctx context.Context, exec bob.Executor) error { + _, err := PublicreportCompliances.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) + return err +} + +// Reload refreshes the PublicreportCompliance using the executor +func (o *PublicreportCompliance) Reload(ctx context.Context, exec bob.Executor) error { + o2, err := PublicreportCompliances.Query( + sm.Where(PublicreportCompliances.Columns.ReportID.EQ(psql.Arg(o.ReportID))), + ).One(ctx, exec) + if err != nil { + return err + } + o2.R = o.R + *o = *o2 + + return nil +} + +// AfterQueryHook is called after PublicreportComplianceSlice is retrieved from the database +func (o PublicreportComplianceSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = PublicreportCompliances.AfterSelectHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeInsert: + ctx, err = PublicreportCompliances.AfterInsertHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeUpdate: + ctx, err = PublicreportCompliances.AfterUpdateHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeDelete: + ctx, err = PublicreportCompliances.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err +} + +func (o PublicreportComplianceSlice) pkIN() dialect.Expression { + if len(o) == 0 { + return psql.Raw("NULL") + } + + return psql.Quote("publicreport.compliance", "report_id").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + pkPairs := make([]bob.Expression, len(o)) + for i, row := range o { + pkPairs[i] = row.primaryKeyVals() + } + return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") + })) +} + +// copyMatchingRows finds models in the given slice that have the same primary key +// then it first copies the existing relationships from the old model to the new model +// and then replaces the old model in the slice with the new model +func (o PublicreportComplianceSlice) copyMatchingRows(from ...*PublicreportCompliance) { + for i, old := range o { + for _, new := range from { + if new.ReportID != old.ReportID { + continue + } + new.R = old.R + o[i] = new + break + } + } +} + +// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" +func (o PublicreportComplianceSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportCompliances.BeforeUpdateHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *PublicreportCompliance: + o.copyMatchingRows(retrieved) + case []*PublicreportCompliance: + o.copyMatchingRows(retrieved...) + case PublicreportComplianceSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a PublicreportCompliance or a slice of PublicreportCompliance + // then run the AfterUpdateHooks on the slice + _, err = PublicreportCompliances.AfterUpdateHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" +func (o PublicreportComplianceSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { + return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return PublicreportCompliances.BeforeDeleteHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *PublicreportCompliance: + o.copyMatchingRows(retrieved) + case []*PublicreportCompliance: + o.copyMatchingRows(retrieved...) + case PublicreportComplianceSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a PublicreportCompliance or a slice of PublicreportCompliance + // then run the AfterDeleteHooks on the slice + _, err = PublicreportCompliances.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +func (o PublicreportComplianceSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals PublicreportComplianceSetter) error { + if len(o) == 0 { + return nil + } + + _, err := PublicreportCompliances.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) + return err +} + +func (o PublicreportComplianceSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + _, err := PublicreportCompliances.Delete(o.DeleteMod()).Exec(ctx, exec) + return err +} + +func (o PublicreportComplianceSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + o2, err := PublicreportCompliances.Query(sm.Where(o.pkIN())).All(ctx, exec) + if err != nil { + return err + } + + o.copyMatchingRows(o2...) + + return nil +} + +// Report starts a query for related objects on publicreport.report +func (o *PublicreportCompliance) Report(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportReportsQuery { + return PublicreportReports.Query(append(mods, + sm.Where(PublicreportReports.Columns.ID.EQ(psql.Arg(o.ReportID))), + )...) +} + +func (os PublicreportComplianceSlice) Report(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportReportsQuery { + pkReportID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkReportID = append(pkReportID, o.ReportID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkReportID), "integer[]")), + )) + + return PublicreportReports.Query(append(mods, + sm.Where(psql.Group(PublicreportReports.Columns.ID).OP("IN", PKArgExpr)), + )...) +} + +func attachPublicreportComplianceReport0(ctx context.Context, exec bob.Executor, count int, publicreportCompliance0 *PublicreportCompliance, publicreportReport1 *PublicreportReport) (*PublicreportCompliance, error) { + setter := &PublicreportComplianceSetter{ + ReportID: omit.From(publicreportReport1.ID), + } + + err := publicreportCompliance0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachPublicreportComplianceReport0: %w", err) + } + + return publicreportCompliance0, nil +} + +func (publicreportCompliance0 *PublicreportCompliance) InsertReport(ctx context.Context, exec bob.Executor, related *PublicreportReportSetter) error { + var err error + + publicreportReport1, err := PublicreportReports.Insert(related).One(ctx, exec) + if err != nil { + return fmt.Errorf("inserting related objects: %w", err) + } + + _, err = attachPublicreportComplianceReport0(ctx, exec, 1, publicreportCompliance0, publicreportReport1) + if err != nil { + return err + } + + publicreportCompliance0.R.Report = publicreportReport1 + + publicreportReport1.R.Compliance = publicreportCompliance0 + + return nil +} + +func (publicreportCompliance0 *PublicreportCompliance) AttachReport(ctx context.Context, exec bob.Executor, publicreportReport1 *PublicreportReport) error { + var err error + + _, err = attachPublicreportComplianceReport0(ctx, exec, 1, publicreportCompliance0, publicreportReport1) + if err != nil { + return err + } + + publicreportCompliance0.R.Report = publicreportReport1 + + publicreportReport1.R.Compliance = publicreportCompliance0 + + return nil +} + +type publicreportComplianceWhere[Q psql.Filterable] struct { + AccessInstructions psql.WhereMod[Q, string] + AvailabilityNotes psql.WhereMod[Q, string] + Comments psql.WhereMod[Q, string] + GateCode psql.WhereMod[Q, string] + HasDog psql.WhereNullMod[Q, bool] + PermissionType psql.WhereMod[Q, enums.Permissionaccesstype] + ReportID psql.WhereMod[Q, int32] + ReportPhoneCanText psql.WhereNullMod[Q, bool] + WantsScheduled psql.WhereNullMod[Q, bool] +} + +func (publicreportComplianceWhere[Q]) AliasedAs(alias string) publicreportComplianceWhere[Q] { + return buildPublicreportComplianceWhere[Q](buildPublicreportComplianceColumns(alias)) +} + +func buildPublicreportComplianceWhere[Q psql.Filterable](cols publicreportComplianceColumns) publicreportComplianceWhere[Q] { + return publicreportComplianceWhere[Q]{ + AccessInstructions: psql.Where[Q, string](cols.AccessInstructions), + AvailabilityNotes: psql.Where[Q, string](cols.AvailabilityNotes), + Comments: psql.Where[Q, string](cols.Comments), + GateCode: psql.Where[Q, string](cols.GateCode), + HasDog: psql.WhereNull[Q, bool](cols.HasDog), + PermissionType: psql.Where[Q, enums.Permissionaccesstype](cols.PermissionType), + ReportID: psql.Where[Q, int32](cols.ReportID), + ReportPhoneCanText: psql.WhereNull[Q, bool](cols.ReportPhoneCanText), + WantsScheduled: psql.WhereNull[Q, bool](cols.WantsScheduled), + } +} + +func (o *PublicreportCompliance) Preload(name string, retrieved any) error { + if o == nil { + return nil + } + + switch name { + case "Report": + rel, ok := retrieved.(*PublicreportReport) + if !ok { + return fmt.Errorf("publicreportCompliance cannot load %T as %q", retrieved, name) + } + + o.R.Report = rel + + if rel != nil { + rel.R.Compliance = o + } + return nil + default: + return fmt.Errorf("publicreportCompliance has no relationship %q", name) + } +} + +type publicreportCompliancePreloader struct { + Report func(...psql.PreloadOption) psql.Preloader +} + +func buildPublicreportCompliancePreloader() publicreportCompliancePreloader { + return publicreportCompliancePreloader{ + Report: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*PublicreportReport, PublicreportReportSlice](psql.PreloadRel{ + Name: "Report", + Sides: []psql.PreloadSide{ + { + From: PublicreportCompliances, + To: PublicreportReports, + FromColumns: []string{"report_id"}, + ToColumns: []string{"id"}, + }, + }, + }, PublicreportReports.Columns.Names(), opts...) + }, + } +} + +type publicreportComplianceThenLoader[Q orm.Loadable] struct { + Report func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildPublicreportComplianceThenLoader[Q orm.Loadable]() publicreportComplianceThenLoader[Q] { + type ReportLoadInterface interface { + LoadReport(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return publicreportComplianceThenLoader[Q]{ + Report: thenLoadBuilder[Q]( + "Report", + func(ctx context.Context, exec bob.Executor, retrieved ReportLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadReport(ctx, exec, mods...) + }, + ), + } +} + +// LoadReport loads the publicreportCompliance's Report into the .R struct +func (o *PublicreportCompliance) LoadReport(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Report = nil + + related, err := o.Report(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.Compliance = o + + o.R.Report = related + return nil +} + +// LoadReport loads the publicreportCompliance's Report into the .R struct +func (os PublicreportComplianceSlice) LoadReport(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + publicreportReports, err := os.Report(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range publicreportReports { + + if !(o.ReportID == rel.ID) { + continue + } + + rel.R.Compliance = o + + o.R.Report = rel + break + } + } + + return nil +} diff --git a/db/models/publicreport.report.bob.go b/db/models/publicreport.report.bob.go index 1bbbfad5..b8afc50f 100644 --- a/db/models/publicreport.report.bob.go +++ b/db/models/publicreport.report.bob.go @@ -22,6 +22,7 @@ import ( "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" "github.com/aarondl/opt/omitnull" + "github.com/google/uuid" "github.com/stephenafamo/scan" ) @@ -55,6 +56,7 @@ type PublicreportReport struct { LocationLatitude null.Val[float64] `db:"location_latitude,generated" ` LocationLongitude null.Val[float64] `db:"location_longitude,generated" ` AddressGid string `db:"address_gid" ` + ClientUUID null.Val[uuid.UUID] `db:"client_uuid" ` R publicreportReportR `db:"-" ` } @@ -72,10 +74,12 @@ type PublicreportReportsQuery = *psql.ViewQuery[*PublicreportReport, Publicrepor // publicreportReportR is where relationships are stored. type publicreportReportR struct { TextJobs CommsTextJobSlice // comms.text_job.text_job_report_id_fkey + Compliance *PublicreportCompliance // publicreport.compliance.compliance_report_id_fkey NotifyEmails PublicreportNotifyEmailSlice // publicreport.notify_email.notify_email_report_id_fkey NotifyPhones PublicreportNotifyPhoneSlice // publicreport.notify_phone.notify_phone_report_id_fkey Nuisance *PublicreportNuisance // publicreport.nuisance.nuisance_report_id_fkey Address *Address // publicreport.report.report_address_id_fkey + Client *PublicreportClient // publicreport.report.report_client_uuid_fkey Organization *Organization // publicreport.report.report_organization_id_fkey ReviewerUser *User // publicreport.report.report_reviewer_id_fkey Images PublicreportImageSlice // publicreport.report_image.report_image_image_id_fkeypublicreport.report_image.report_image_report_id_fkey @@ -88,7 +92,7 @@ type publicreportReportR struct { func buildPublicreportReportColumns(alias string) publicreportReportColumns { return publicreportReportColumns{ ColumnsExpr: expr.NewColumnsExpr( - "address_raw", "address_number", "address_street", "address_locality", "address_region", "address_postal_code", "address_country", "address_id", "created", "location", "h3cell", "id", "latlng_accuracy_type", "latlng_accuracy_value", "map_zoom", "organization_id", "public_id", "reporter_name", "reporter_email", "reporter_phone", "reporter_contact_consent", "report_type", "reviewed", "reviewer_id", "status", "location_latitude", "location_longitude", "address_gid", + "address_raw", "address_number", "address_street", "address_locality", "address_region", "address_postal_code", "address_country", "address_id", "created", "location", "h3cell", "id", "latlng_accuracy_type", "latlng_accuracy_value", "map_zoom", "organization_id", "public_id", "reporter_name", "reporter_email", "reporter_phone", "reporter_contact_consent", "report_type", "reviewed", "reviewer_id", "status", "location_latitude", "location_longitude", "address_gid", "client_uuid", ).WithParent("publicreport.report"), tableAlias: alias, AddressRaw: psql.Quote(alias, "address_raw"), @@ -119,6 +123,7 @@ func buildPublicreportReportColumns(alias string) publicreportReportColumns { LocationLatitude: psql.Quote(alias, "location_latitude"), LocationLongitude: psql.Quote(alias, "location_longitude"), AddressGid: psql.Quote(alias, "address_gid"), + ClientUUID: psql.Quote(alias, "client_uuid"), } } @@ -153,6 +158,7 @@ type publicreportReportColumns struct { LocationLatitude psql.Expression LocationLongitude psql.Expression AddressGid psql.Expression + ClientUUID psql.Expression } func (c publicreportReportColumns) Alias() string { @@ -193,10 +199,11 @@ type PublicreportReportSetter struct { ReviewerID omitnull.Val[int32] `db:"reviewer_id" ` Status omit.Val[enums.PublicreportReportstatustype] `db:"status" ` AddressGid omit.Val[string] `db:"address_gid" ` + ClientUUID omitnull.Val[uuid.UUID] `db:"client_uuid" ` } func (s PublicreportReportSetter) SetColumns() []string { - vals := make([]string, 0, 26) + vals := make([]string, 0, 27) if s.AddressRaw.IsValue() { vals = append(vals, "address_raw") } @@ -275,6 +282,9 @@ func (s PublicreportReportSetter) SetColumns() []string { if s.AddressGid.IsValue() { vals = append(vals, "address_gid") } + if !s.ClientUUID.IsUnset() { + vals = append(vals, "client_uuid") + } return vals } @@ -357,6 +367,9 @@ func (s PublicreportReportSetter) Overwrite(t *PublicreportReport) { if s.AddressGid.IsValue() { t.AddressGid = s.AddressGid.MustGet() } + if !s.ClientUUID.IsUnset() { + t.ClientUUID = s.ClientUUID.MustGetNull() + } } func (s *PublicreportReportSetter) Apply(q *dialect.InsertQuery) { @@ -365,7 +378,7 @@ func (s *PublicreportReportSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 26) + vals := make([]bob.Expression, 27) if s.AddressRaw.IsValue() { vals[0] = psql.Arg(s.AddressRaw.MustGet()) } else { @@ -522,6 +535,12 @@ func (s *PublicreportReportSetter) Apply(q *dialect.InsertQuery) { vals[25] = psql.Raw("DEFAULT") } + if !s.ClientUUID.IsUnset() { + vals[26] = psql.Arg(s.ClientUUID.MustGetNull()) + } else { + vals[26] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -531,7 +550,7 @@ func (s PublicreportReportSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s PublicreportReportSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 26) + exprs := make([]bob.Expression, 0, 27) if s.AddressRaw.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -715,6 +734,13 @@ func (s PublicreportReportSetter) Expressions(prefix ...string) []bob.Expression }}) } + if !s.ClientUUID.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "client_uuid")...), + psql.Arg(s.ClientUUID), + }}) + } + return exprs } @@ -965,6 +991,30 @@ func (os PublicreportReportSlice) TextJobs(mods ...bob.Mod[*dialect.SelectQuery] )...) } +// Compliance starts a query for related objects on publicreport.compliance +func (o *PublicreportReport) Compliance(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportCompliancesQuery { + return PublicreportCompliances.Query(append(mods, + sm.Where(PublicreportCompliances.Columns.ReportID.EQ(psql.Arg(o.ID))), + )...) +} + +func (os PublicreportReportSlice) Compliance(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportCompliancesQuery { + pkID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkID = append(pkID, o.ID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkID), "integer[]")), + )) + + return PublicreportCompliances.Query(append(mods, + sm.Where(psql.Group(PublicreportCompliances.Columns.ReportID).OP("IN", PKArgExpr)), + )...) +} + // NotifyEmails starts a query for related objects on publicreport.notify_email func (o *PublicreportReport) NotifyEmails(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportNotifyEmailsQuery { return PublicreportNotifyEmails.Query(append(mods, @@ -1061,6 +1111,30 @@ func (os PublicreportReportSlice) Address(mods ...bob.Mod[*dialect.SelectQuery]) )...) } +// Client starts a query for related objects on publicreport.client +func (o *PublicreportReport) Client(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportClientsQuery { + return PublicreportClients.Query(append(mods, + sm.Where(PublicreportClients.Columns.UUID.EQ(psql.Arg(o.ClientUUID))), + )...) +} + +func (os PublicreportReportSlice) Client(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportClientsQuery { + pkClientUUID := make(pgtypes.Array[null.Val[uuid.UUID]], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkClientUUID = append(pkClientUUID, o.ClientUUID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkClientUUID), "uuid[]")), + )) + + return PublicreportClients.Query(append(mods, + sm.Where(psql.Group(PublicreportClients.Columns.UUID).OP("IN", PKArgExpr)), + )...) +} + // Organization starts a query for related objects on organization func (o *PublicreportReport) Organization(mods ...bob.Mod[*dialect.SelectQuery]) OrganizationsQuery { return Organizations.Query(append(mods, @@ -1302,6 +1376,60 @@ func (publicreportReport0 *PublicreportReport) AttachTextJobs(ctx context.Contex return nil } +func insertPublicreportReportCompliance0(ctx context.Context, exec bob.Executor, publicreportCompliance1 *PublicreportComplianceSetter, publicreportReport0 *PublicreportReport) (*PublicreportCompliance, error) { + publicreportCompliance1.ReportID = omit.From(publicreportReport0.ID) + + ret, err := PublicreportCompliances.Insert(publicreportCompliance1).One(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertPublicreportReportCompliance0: %w", err) + } + + return ret, nil +} + +func attachPublicreportReportCompliance0(ctx context.Context, exec bob.Executor, count int, publicreportCompliance1 *PublicreportCompliance, publicreportReport0 *PublicreportReport) (*PublicreportCompliance, error) { + setter := &PublicreportComplianceSetter{ + ReportID: omit.From(publicreportReport0.ID), + } + + err := publicreportCompliance1.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachPublicreportReportCompliance0: %w", err) + } + + return publicreportCompliance1, nil +} + +func (publicreportReport0 *PublicreportReport) InsertCompliance(ctx context.Context, exec bob.Executor, related *PublicreportComplianceSetter) error { + var err error + + publicreportCompliance1, err := insertPublicreportReportCompliance0(ctx, exec, related, publicreportReport0) + if err != nil { + return err + } + + publicreportReport0.R.Compliance = publicreportCompliance1 + + publicreportCompliance1.R.Report = publicreportReport0 + + return nil +} + +func (publicreportReport0 *PublicreportReport) AttachCompliance(ctx context.Context, exec bob.Executor, publicreportCompliance1 *PublicreportCompliance) error { + var err error + + _, err = attachPublicreportReportCompliance0(ctx, exec, 1, publicreportCompliance1, publicreportReport0) + if err != nil { + return err + } + + publicreportReport0.R.Compliance = publicreportCompliance1 + + publicreportCompliance1.R.Report = publicreportReport0 + + return nil +} + func insertPublicreportReportNotifyEmails0(ctx context.Context, exec bob.Executor, publicreportNotifyEmails1 []*PublicreportNotifyEmailSetter, publicreportReport0 *PublicreportReport) (PublicreportNotifyEmailSlice, error) { for i := range publicreportNotifyEmails1 { publicreportNotifyEmails1[i].ReportID = omit.From(publicreportReport0.ID) @@ -1540,6 +1668,54 @@ func (publicreportReport0 *PublicreportReport) AttachAddress(ctx context.Context return nil } +func attachPublicreportReportClient0(ctx context.Context, exec bob.Executor, count int, publicreportReport0 *PublicreportReport, publicreportClient1 *PublicreportClient) (*PublicreportReport, error) { + setter := &PublicreportReportSetter{ + ClientUUID: omitnull.From(publicreportClient1.UUID), + } + + err := publicreportReport0.Update(ctx, exec, setter) + if err != nil { + return nil, fmt.Errorf("attachPublicreportReportClient0: %w", err) + } + + return publicreportReport0, nil +} + +func (publicreportReport0 *PublicreportReport) InsertClient(ctx context.Context, exec bob.Executor, related *PublicreportClientSetter) error { + var err error + + publicreportClient1, err := PublicreportClients.Insert(related).One(ctx, exec) + if err != nil { + return fmt.Errorf("inserting related objects: %w", err) + } + + _, err = attachPublicreportReportClient0(ctx, exec, 1, publicreportReport0, publicreportClient1) + if err != nil { + return err + } + + publicreportReport0.R.Client = publicreportClient1 + + publicreportClient1.R.Reports = append(publicreportClient1.R.Reports, publicreportReport0) + + return nil +} + +func (publicreportReport0 *PublicreportReport) AttachClient(ctx context.Context, exec bob.Executor, publicreportClient1 *PublicreportClient) error { + var err error + + _, err = attachPublicreportReportClient0(ctx, exec, 1, publicreportReport0, publicreportClient1) + if err != nil { + return err + } + + publicreportReport0.R.Client = publicreportClient1 + + publicreportClient1.R.Reports = append(publicreportClient1.R.Reports, publicreportReport0) + + return nil +} + func attachPublicreportReportOrganization0(ctx context.Context, exec bob.Executor, count int, publicreportReport0 *PublicreportReport, organization1 *Organization) (*PublicreportReport, error) { setter := &PublicreportReportSetter{ OrganizationID: omit.From(organization1.ID), @@ -1988,6 +2164,7 @@ type publicreportReportWhere[Q psql.Filterable] struct { LocationLatitude psql.WhereNullMod[Q, float64] LocationLongitude psql.WhereNullMod[Q, float64] AddressGid psql.WhereMod[Q, string] + ClientUUID psql.WhereNullMod[Q, uuid.UUID] } func (publicreportReportWhere[Q]) AliasedAs(alias string) publicreportReportWhere[Q] { @@ -2024,6 +2201,7 @@ func buildPublicreportReportWhere[Q psql.Filterable](cols publicreportReportColu LocationLatitude: psql.WhereNull[Q, float64](cols.LocationLatitude), LocationLongitude: psql.WhereNull[Q, float64](cols.LocationLongitude), AddressGid: psql.Where[Q, string](cols.AddressGid), + ClientUUID: psql.WhereNull[Q, uuid.UUID](cols.ClientUUID), } } @@ -2047,6 +2225,18 @@ func (o *PublicreportReport) Preload(name string, retrieved any) error { } } return nil + case "Compliance": + rel, ok := retrieved.(*PublicreportCompliance) + if !ok { + return fmt.Errorf("publicreportReport cannot load %T as %q", retrieved, name) + } + + o.R.Compliance = rel + + if rel != nil { + rel.R.Report = o + } + return nil case "NotifyEmails": rels, ok := retrieved.(PublicreportNotifyEmailSlice) if !ok { @@ -2095,6 +2285,18 @@ func (o *PublicreportReport) Preload(name string, retrieved any) error { o.R.Address = rel + if rel != nil { + rel.R.Reports = PublicreportReportSlice{o} + } + return nil + case "Client": + rel, ok := retrieved.(*PublicreportClient) + if !ok { + return fmt.Errorf("publicreportReport cannot load %T as %q", retrieved, name) + } + + o.R.Client = rel + if rel != nil { rel.R.Reports = PublicreportReportSlice{o} } @@ -2197,8 +2399,10 @@ func (o *PublicreportReport) Preload(name string, retrieved any) error { } type publicreportReportPreloader struct { + Compliance func(...psql.PreloadOption) psql.Preloader Nuisance func(...psql.PreloadOption) psql.Preloader Address func(...psql.PreloadOption) psql.Preloader + Client func(...psql.PreloadOption) psql.Preloader Organization func(...psql.PreloadOption) psql.Preloader ReviewerUser func(...psql.PreloadOption) psql.Preloader Water func(...psql.PreloadOption) psql.Preloader @@ -2206,6 +2410,19 @@ type publicreportReportPreloader struct { func buildPublicreportReportPreloader() publicreportReportPreloader { return publicreportReportPreloader{ + Compliance: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*PublicreportCompliance, PublicreportComplianceSlice](psql.PreloadRel{ + Name: "Compliance", + Sides: []psql.PreloadSide{ + { + From: PublicreportReports, + To: PublicreportCompliances, + FromColumns: []string{"id"}, + ToColumns: []string{"report_id"}, + }, + }, + }, PublicreportCompliances.Columns.Names(), opts...) + }, Nuisance: func(opts ...psql.PreloadOption) psql.Preloader { return psql.Preload[*PublicreportNuisance, PublicreportNuisanceSlice](psql.PreloadRel{ Name: "Nuisance", @@ -2232,6 +2449,19 @@ func buildPublicreportReportPreloader() publicreportReportPreloader { }, }, Addresses.Columns.Names(), opts...) }, + Client: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*PublicreportClient, PublicreportClientSlice](psql.PreloadRel{ + Name: "Client", + Sides: []psql.PreloadSide{ + { + From: PublicreportReports, + To: PublicreportClients, + FromColumns: []string{"client_uuid"}, + ToColumns: []string{"uuid"}, + }, + }, + }, PublicreportClients.Columns.Names(), opts...) + }, Organization: func(opts ...psql.PreloadOption) psql.Preloader { return psql.Preload[*Organization, OrganizationSlice](psql.PreloadRel{ Name: "Organization", @@ -2276,10 +2506,12 @@ func buildPublicreportReportPreloader() publicreportReportPreloader { type publicreportReportThenLoader[Q orm.Loadable] struct { TextJobs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + Compliance func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] NotifyEmails func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] NotifyPhones func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Nuisance func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Address func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + Client func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Organization func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] ReviewerUser func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] Images func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] @@ -2293,6 +2525,9 @@ func buildPublicreportReportThenLoader[Q orm.Loadable]() publicreportReportThenL type TextJobsLoadInterface interface { LoadTextJobs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type ComplianceLoadInterface interface { + LoadCompliance(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type NotifyEmailsLoadInterface interface { LoadNotifyEmails(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -2305,6 +2540,9 @@ func buildPublicreportReportThenLoader[Q orm.Loadable]() publicreportReportThenL type AddressLoadInterface interface { LoadAddress(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } + type ClientLoadInterface interface { + LoadClient(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } type OrganizationLoadInterface interface { LoadOrganization(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -2334,6 +2572,12 @@ func buildPublicreportReportThenLoader[Q orm.Loadable]() publicreportReportThenL return retrieved.LoadTextJobs(ctx, exec, mods...) }, ), + Compliance: thenLoadBuilder[Q]( + "Compliance", + func(ctx context.Context, exec bob.Executor, retrieved ComplianceLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCompliance(ctx, exec, mods...) + }, + ), NotifyEmails: thenLoadBuilder[Q]( "NotifyEmails", func(ctx context.Context, exec bob.Executor, retrieved NotifyEmailsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -2358,6 +2602,12 @@ func buildPublicreportReportThenLoader[Q orm.Loadable]() publicreportReportThenL return retrieved.LoadAddress(ctx, exec, mods...) }, ), + Client: thenLoadBuilder[Q]( + "Client", + func(ctx context.Context, exec bob.Executor, retrieved ClientLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadClient(ctx, exec, mods...) + }, + ), Organization: thenLoadBuilder[Q]( "Organization", func(ctx context.Context, exec bob.Executor, retrieved OrganizationLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -2467,6 +2717,58 @@ func (os PublicreportReportSlice) LoadTextJobs(ctx context.Context, exec bob.Exe return nil } +// LoadCompliance loads the publicreportReport's Compliance into the .R struct +func (o *PublicreportReport) LoadCompliance(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Compliance = nil + + related, err := o.Compliance(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.Report = o + + o.R.Compliance = related + return nil +} + +// LoadCompliance loads the publicreportReport's Compliance into the .R struct +func (os PublicreportReportSlice) LoadCompliance(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + publicreportCompliances, err := os.Compliance(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range publicreportCompliances { + + if !(o.ID == rel.ReportID) { + continue + } + + rel.R.Report = o + + o.R.Compliance = rel + break + } + } + + return nil +} + // LoadNotifyEmails loads the publicreportReport's NotifyEmails into the .R struct func (o *PublicreportReport) LoadNotifyEmails(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -2696,6 +2998,61 @@ func (os PublicreportReportSlice) LoadAddress(ctx context.Context, exec bob.Exec return nil } +// LoadClient loads the publicreportReport's Client into the .R struct +func (o *PublicreportReport) LoadClient(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.Client = nil + + related, err := o.Client(mods...).One(ctx, exec) + if err != nil { + return err + } + + related.R.Reports = PublicreportReportSlice{o} + + o.R.Client = related + return nil +} + +// LoadClient loads the publicreportReport's Client into the .R struct +func (os PublicreportReportSlice) LoadClient(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + publicreportClients, err := os.Client(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range publicreportClients { + if !o.ClientUUID.IsValue() { + continue + } + + if !(o.ClientUUID.IsValue() && o.ClientUUID.MustGet() == rel.UUID) { + continue + } + + rel.R.Reports = append(rel.R.Reports, o) + + o.R.Client = rel + break + } + } + + return nil +} + // LoadOrganization loads the publicreportReport's Organization into the .R struct func (o *PublicreportReport) LoadOrganization(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { diff --git a/platform/publicreport.go b/platform/publicreport.go index 2fb175ea..f2c719b0 100644 --- a/platform/publicreport.go +++ b/platform/publicreport.go @@ -84,8 +84,18 @@ func PublicReportMessageCreate(ctx context.Context, user User, report_id, messag func PublicReportReporterUpdated(ctx context.Context, org_id int32, report_id string) { event.Updated(event.TypeRMOReport, org_id, report_id) } +func ReportComplianceCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_compliance models.PublicreportComplianceSetter) (*models.PublicreportReport, error) { + return reportCreate(ctx, setter_report, nil, nil, nil, func(ctx context.Context, txn bob.Executor, report_id int32) error { + setter_compliance.ReportID = omit.From(report_id) + _, err := models.PublicreportCompliances.Insert(&setter_compliance).One(ctx, txn) + if err != nil { + return fmt.Errorf("Failed to create nuisance database record: %w", err) + } + return nil + }) +} func ReportNuisanceCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_nuisance models.PublicreportNuisanceSetter, location types.Location, address Address, images []ImageUpload) (*models.PublicreportReport, error) { - return reportCreate(ctx, setter_report, location, address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { + return reportCreate(ctx, setter_report, &location, &address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { setter_nuisance.ReportID = omit.From(report_id) _, err := models.PublicreportNuisances.Insert(&setter_nuisance).One(ctx, txn) if err != nil { @@ -96,7 +106,7 @@ func ReportNuisanceCreate(ctx context.Context, setter_report models.Publicreport } func ReportWaterCreate(ctx context.Context, setter_report models.PublicreportReportSetter, setter_water models.PublicreportWaterSetter, location types.Location, address Address, images []ImageUpload) (*models.PublicreportReport, error) { - return reportCreate(ctx, setter_report, location, address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { + return reportCreate(ctx, setter_report, &location, &address, images, func(ctx context.Context, txn bob.Executor, report_id int32) error { setter_water.ReportID = omit.From(report_id) _, err := models.PublicreportWaters.Insert(&setter_water).One(ctx, txn) if err != nil { @@ -108,7 +118,7 @@ func ReportWaterCreate(ctx context.Context, setter_report models.PublicreportRep type funcSetReportDetail = func(context.Context, bob.Executor, int32) error -func reportCreate(ctx context.Context, setter_report models.PublicreportReportSetter, location types.Location, address Address, images []ImageUpload, detail_setter funcSetReportDetail) (result *models.PublicreportReport, err error) { +func reportCreate(ctx context.Context, setter_report models.PublicreportReportSetter, location *types.Location, address *Address, images []ImageUpload, detail_setter funcSetReportDetail) (result *models.PublicreportReport, err error) { txn, err := db.PGInstance.BobDB.BeginTx(ctx, nil) if err != nil { return nil, fmt.Errorf("create txn: %w", err) @@ -122,14 +132,18 @@ func reportCreate(ctx context.Context, setter_report models.PublicreportReportSe setter_report.PublicID = omit.From(public_id) // If we've got an locality value it was set by geocoding so we should save it - var a *models.Address - if address.Locality != "" && location.Latitude != 0 && location.Longitude != 0 { - a, err = geocode.EnsureAddress(ctx, txn, address, types.Location{ - Latitude: location.Latitude, - Longitude: location.Longitude, - }) - if err != nil { - return nil, fmt.Errorf("Failed to ensure address: %w", err) + var addr *models.Address + if address != nil && location != nil { + a := *address + l := *location + if a.Locality != "" && l.Latitude != 0 && l.Longitude != 0 { + addr, err = geocode.EnsureAddress(ctx, txn, a, types.Location{ + Latitude: l.Latitude, + Longitude: l.Longitude, + }) + if err != nil { + return nil, fmt.Errorf("Failed to ensure address: %w", err) + } } } @@ -143,8 +157,8 @@ func reportCreate(ctx context.Context, setter_report models.PublicreportReportSe log.Warn().Err(err).Msg("Failed to match district") } - if a != nil { - setter_report.AddressID = omitnull.From(a.ID) + if addr != nil { + setter_report.AddressID = omitnull.From(addr.ID) } if organization_id != nil { setter_report.OrganizationID = omit.FromPtr(organization_id) @@ -153,17 +167,20 @@ func reportCreate(ctx context.Context, setter_report models.PublicreportReportSe if err != nil { return nil, fmt.Errorf("Failed to create report database record: %w", err) } - if location.Latitude != 0 && location.Longitude != 0 { - h3cell, _ := location.H3Cell() - geom_query, _ := location.GeometryQuery() - _, err = psql.Update( - um.Table("publicreport.report"), - um.SetCol("h3cell").ToArg(h3cell), - um.SetCol("location").To(geom_query), - um.Where(psql.Quote("id").EQ(psql.Arg(result.ID))), - ).Exec(ctx, txn) - if err != nil { - return nil, fmt.Errorf("Failed to insert publicreport.report geospatial", err) + if location != nil { + l := *location + if l.Latitude != 0 && l.Longitude != 0 { + h3cell, _ := location.H3Cell() + geom_query, _ := location.GeometryQuery() + _, err = psql.Update( + um.Table("publicreport.report"), + um.SetCol("h3cell").ToArg(h3cell), + um.SetCol("location").To(geom_query), + um.Where(psql.Quote("id").EQ(psql.Arg(result.ID))), + ).Exec(ctx, txn) + if err != nil { + return nil, fmt.Errorf("Failed to insert publicreport.report geospatial", err) + } } } log.Info().Str("public_id", public_id).Int32("id", result.ID).Msg("Created base report") diff --git a/resource/compliance.go b/resource/compliance.go new file mode 100644 index 00000000..11a8b4ef --- /dev/null +++ b/resource/compliance.go @@ -0,0 +1,111 @@ +package resource + +import ( + "context" + "net/http" + "time" + + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/Gleipnir-Technology/nidus-sync/html" + nhttp "github.com/Gleipnir-Technology/nidus-sync/http" + "github.com/Gleipnir-Technology/nidus-sync/platform" + "github.com/Gleipnir-Technology/nidus-sync/platform/types" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/rs/zerolog/log" +) + +func Compliance(r *router) *complianceR { + return &complianceR{ + router: r, + } +} + +type complianceR struct { + router *router +} +type compliance struct { + District string `json:"district"` + ID string `json:"id"` + URI string `json:"uri"` +} +type complianceForm struct { + DistrictID string `schema:"district"` + Location *types.Location `schema:"location"` + Locator *Locator `schema:"locator"` + ClientID string `schema:"client_id"` +} + +func (res *complianceR) Create(ctx context.Context, r *http.Request, n complianceForm) (*compliance, *nhttp.ErrorWithStatus) { + setter_report := models.PublicreportReportSetter{ + //AddressID: omitnull.From(latlng.Cell.String()), + AddressCountry: omit.From(""), + AddressGid: omit.From(""), + AddressNumber: omit.From(""), + AddressLocality: omit.From(""), + AddressPostalCode: omit.From(""), + AddressRaw: omit.From(""), + AddressRegion: omit.From(""), + AddressStreet: omit.From(""), + Created: omit.From(time.Now()), + //H3cell: omitnull.From(latlng.Cell.String()), + LatlngAccuracyType: omit.From(enums.PublicreportAccuracytypeBrowser), + LatlngAccuracyValue: omit.From(float32(0.0)), + //Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)), + Location: omitnull.FromPtr[string](nil), + MapZoom: omit.From(float32(0.0)), + //OrganizationID: omitnull.FromPtr(organization_id), + //PublicID: omit.From(public_id), + ReporterEmail: omit.From(""), + ReporterName: omit.From(""), + ReporterPhone: omit.From(""), + ReportType: omit.From(enums.PublicreportReporttypeNuisance), + Status: omit.From(enums.PublicreportReportstatustypeReported), + } + setter_compliance := models.PublicreportComplianceSetter{ + AccessInstructions: omit.From(""), + AvailabilityNotes: omit.From(""), + Comments: omit.From(""), + GateCode: omit.From(""), + HasDog: omitnull.FromPtr[bool](nil), + PermissionType: omit.From(enums.PermissionaccesstypeUnselected), + //ReportID omit.Val[int32] + ReportPhoneCanText: omitnull.FromPtr[bool](nil), + WantsScheduled: omitnull.FromPtr[bool](nil), + } + report, err := platform.ReportComplianceCreate(ctx, setter_report, setter_compliance) + if err != nil { + return nil, nhttp.NewError("create compliance report: %w", err) + } + uri, err := res.router.IDStrToURI("publicreport.ByIDGet", report.PublicID) + if err != nil { + return nil, nhttp.NewError("generate uri: %w", err) + } + district_uri, err := res.router.IDToURI("district.ByIDGet", int(report.OrganizationID)) + if err != nil { + return nil, nhttp.NewError("generate district uri: %w", err) + } + return &compliance{ + District: district_uri, + ID: report.PublicID, + URI: uri, + }, nil +} +func (res *complianceR) Update(ctx context.Context, r *http.Request, n complianceForm) (*compliance, *nhttp.ErrorWithStatus) { + uploads, err := html.ExtractImageUploads(r) + log.Info().Int("len", len(uploads)).Msg("extracted compliance uploads") + if err != nil { + return nil, nhttp.NewError("Failed to extract image uploads: %w", err) + } + address := platform.Address{ + GID: n.Locator.Address.GID, + Raw: n.Locator.Address.Raw, + } + accuracy := float32(0.0) + if n.Location.Accuracy != nil { + accuracy = *n.Location.Accuracy + } + log.Info().Str("address.raw", address.Raw).Str("address.gid", address.GID).Float32("accuracy", accuracy).Msg("making compliance") + return nil, nil +} diff --git a/ts/rmo/components/AddressAndMapLocator.vue b/ts/rmo/components/AddressAndMapLocator.vue index a59f77d7..4ea7d545 100644 --- a/ts/rmo/components/AddressAndMapLocator.vue +++ b/ts/rmo/components/AddressAndMapLocator.vue @@ -64,7 +64,6 @@ import AddressSuggestion from "@/components/AddressSuggestion.vue"; import MapLocator from "@/components/MapLocator.vue"; import type { Address, Geocode, GeocodeSuggestion, Location } from "@/type/api"; import { useGeocodeStore } from "@/store/geocode"; -import { useLocationStore } from "@/store/location"; import type { Camera, Locator } from "@/type/map"; import type { Marker } from "@/types"; diff --git a/ts/rmo/content/Nuisance.vue b/ts/rmo/content/Nuisance.vue index 8315ccb8..aff76ff6 100644 --- a/ts/rmo/content/Nuisance.vue +++ b/ts/rmo/content/Nuisance.vue @@ -469,7 +469,7 @@ import ImageUpload, { Image } from "@/components/ImageUpload.vue"; import MapLocator from "@/components/MapLocator.vue"; import AddressAndMapLocator from "@/rmo/components/AddressAndMapLocator.vue"; import { useGeocodeStore } from "@/store/geocode"; -import { useLocationStore } from "@/store/location"; +import { useStoreLocation } from "@/store/location"; import { useStorePublicReport } from "@/store/publicreport"; import type { Marker } from "@/types"; import type { @@ -487,7 +487,7 @@ const errorMessage = ref(""); const formElement = ref(null); const images = ref([]); const isSubmitting = ref(false); -const locationStore = useLocationStore(); +const storeLocation = useStoreLocation(); const locator = ref({ address: { country: "", @@ -564,7 +564,7 @@ async function doSubmit() { } } onMounted(() => { - locationStore + storeLocation .get() .then((loc: GeolocationPosition) => { console.log("user geolocation", loc); diff --git a/ts/rmo/content/Water.vue b/ts/rmo/content/Water.vue index 2a85a04e..7aec30f7 100644 --- a/ts/rmo/content/Water.vue +++ b/ts/rmo/content/Water.vue @@ -624,7 +624,7 @@ import ImageUpload, { Image } from "@/components/ImageUpload.vue"; import MapLocator from "@/components/MapLocator.vue"; import Tooltip from "@/components/Tooltip.vue"; import { useGeocodeStore } from "@/store/geocode"; -import { useLocationStore } from "@/store/location"; +import { useStoreLocation } from "@/store/location"; import { useStorePublicReport } from "@/store/publicreport"; import type { Marker } from "@/types"; import type { @@ -656,7 +656,7 @@ const markers = computed((): Marker[] => { return []; } }); -const locationStore = useLocationStore(); +const storeLocation = useStoreLocation(); const locator = ref({ address: { country: "", @@ -769,7 +769,7 @@ async function doSubmit() { } } onMounted(() => { - locationStore + storeLocation .get() .then((loc: GeolocationPosition) => { console.log("user geolocation", loc); diff --git a/ts/rmo/view/Compliance.vue b/ts/rmo/view/Compliance.vue index 2abf7ba1..9204bd47 100644 --- a/ts/rmo/view/Compliance.vue +++ b/ts/rmo/view/Compliance.vue @@ -40,8 +40,10 @@ import { computedAsync } from "@vueuse/core"; import type { Image } from "@/components/ImageUpload.vue"; import { useStoreDistrict } from "@/rmo/store/district"; +import { useStoreLocal } from "@/store/local"; +import { useStoreLocation } from "@/store/location"; import Intro from "@/rmo/content/compliance/Intro.vue"; -import { type District, PermissionAccess } from "@/type/api"; +import { type District, PermissionAccess, type PublicReport } from "@/type/api"; import { Locator } from "@/type/map"; import { type Contact } from "@/rmo/content/compliance/Contact.vue"; import { type Permission } from "@/rmo/content/compliance/Permission.vue"; @@ -95,10 +97,13 @@ const compliance = ref({ }, }); const props = defineProps(); +const report = ref(); const district = computedAsync(async (): Promise => { const districts = await districtStore.list(); return districts.find((district: District) => district.slug == props.slug); }); +const storeLocal = useStoreLocal(); +const storeLocation = useStoreLocation(); function doEvidence() { console.log("evidence", compliance.value); } @@ -111,4 +116,29 @@ function doLocator() { function doPermission() { console.log("permission", compliance.value.permission); } +async function createReport(report_id: string, loc?: GeolocationPosition) { + const formData = new FormData(); + formData.append; + const resp = await fetch("/api/rmo/compliance", { + method: "POST", + body: formData, + // Don't set Content-Type, the borwser should do it + }); + if (!resp.ok) { + const content = await resp.text(); + console.error("Failed to create compliance report", resp.status, content); + } +} +onMounted(() => { + const session_id = storeLocal.getSessionID(); + storeLocation + .get() + .then((loc: GeolocationPosition) => { + createReport(session_id, loc); + }) + .catch((e) => { + console.log("failed to get location", e); + createReport(session_id); + }); +}); diff --git a/ts/store/local.ts b/ts/store/local.ts new file mode 100644 index 00000000..f335e811 --- /dev/null +++ b/ts/store/local.ts @@ -0,0 +1,16 @@ +import { defineStore } from "pinia"; + +export const useStoreLocal = defineStore("local", () => { + function getSessionID(): string { + let id = localStorage.getItem("session_id"); + if (id) { + return id; + } + id = crypto.randomUUID(); + localStorage.setItem("session_id", id.toString()); + return id; + } + return { + getSessionID, + }; +}); diff --git a/ts/store/location.ts b/ts/store/location.ts index a20e569f..4dbe7c4b 100644 --- a/ts/store/location.ts +++ b/ts/store/location.ts @@ -5,7 +5,7 @@ interface GeolocationOptions { timeout?: number; enableHighAccuracy?: boolean; } -export const useLocationStore = defineStore("location", () => { +export const useStoreLocation = defineStore("location", () => { function get(options?: GeolocationOptions): Promise { return new Promise((resolve, reject) => { // Check if geolocation is supported by the browser diff --git a/ts/type/api.ts b/ts/type/api.ts index 6a8e32bb..424c559c 100644 --- a/ts/type/api.ts +++ b/ts/type/api.ts @@ -1,8 +1,8 @@ export enum PermissionAccess { - DENIED = "access-denied", - GRANTED = "access-granted", + DENIED = "denied", + GRANTED = "granted", UNSELECTED = "unselected", - WITH_OWNER = "access-with-owner", + WITH_OWNER = "with-owner", } export interface Address { country: string;