diff --git a/db/migrations/00005_add_event_history_table.sql b/db/migrations/00005_add_event_history_table.sql new file mode 100644 index 0000000..80b9860 --- /dev/null +++ b/db/migrations/00005_add_event_history_table.sql @@ -0,0 +1,22 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE public.event_history ( + event_id UUID NOT NULL PRIMARY KEY, + event_type STRING NOT NULL, + event_start TIMESTAMPTZ NOT NULL, + event_end TIMESTAMPTZ NOT NULL, + target_server UUID NOT NULL REFERENCES public.servers(id) ON DELETE CASCADE, + parameters JSON, + final_state STRING NOT NULL, + final_status JSON +); + +CREATE INDEX evt_history_target ON public.event_history (target_server ASC) INCLUDE (event_type, event_start, event_end); + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE public.event_history; +DROP INDEX evt_history_target; +-- +goose StatementEnd diff --git a/internal/dbtools/fixtures.go b/internal/dbtools/fixtures.go index 2148e64..6cfb7ee 100644 --- a/internal/dbtools/fixtures.go +++ b/internal/dbtools/fixtures.go @@ -12,6 +12,7 @@ import ( "github.com/google/uuid" "github.com/jmoiron/sqlx" + "github.com/pkg/errors" "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/types" @@ -96,6 +97,9 @@ var ( FixtureBiosConfigSet *models.BiosConfigSet FixtureBiosConfigComponents []*models.BiosConfigComponent FixtureBiosConfigSettings [][]*models.BiosConfigSetting + + FixtureEventHistoryServer *models.Server + FixtureEventHistories []*models.EventHistory ) func addFixtures(t *testing.T) error { @@ -170,6 +174,10 @@ func addFixtures(t *testing.T) error { return err } + if err := setupEventHistoryFixtures(ctx, testDB); err != nil { + return err + } + if err := setupConfigSet(ctx, testDB); err != nil { return err } @@ -716,6 +724,58 @@ func setupInventoryFixture(ctx context.Context, db *sqlx.DB) error { return nil } +func setupEventHistoryFixtures(ctx context.Context, db *sqlx.DB) error { + FixtureEventHistoryServer = &models.Server{ + Name: null.StringFrom("event-history"), + FacilityCode: null.StringFrom("tf2"), + } + + if err := FixtureEventHistoryServer.Insert(ctx, db, boil.Infer()); err != nil { + return errors.Wrap(err, "event history server fixture") + } + + FixtureEventHistories = []*models.EventHistory{ + { + EventID: uuid.New().String(), + EventType: "test event", + EventStart: time.Now().Add(-5 * time.Hour), + EventEnd: time.Now().Add(-4 * time.Hour), + TargetServer: FixtureEventHistoryServer.ID, + Parameters: null.JSONFrom([]byte(`{"msg": "test event"}`)), + FinalState: "succeeded", + FinalStatus: null.JSONFrom([]byte(`{"status": "some status"}`)), + }, + { + EventID: uuid.New().String(), + EventType: "test event", + EventStart: time.Now().Add(-3 * time.Hour), + EventEnd: time.Now().Add(-2 * time.Hour), + TargetServer: FixtureEventHistoryServer.ID, + Parameters: null.JSONFrom([]byte(`{"msg": "test event"}`)), + FinalState: "failed", + FinalStatus: null.JSONFrom([]byte(`{"status": "bad status"}`)), + }, + { + EventID: uuid.New().String(), + EventType: "test event", + EventStart: time.Now().Add(-1 * time.Hour), + EventEnd: time.Now().Add(-30 * time.Minute), + TargetServer: FixtureEventHistoryServer.ID, + Parameters: null.JSONFrom([]byte(`{"msg": "test event"}`)), + FinalState: "succeeded", + FinalStatus: null.JSONFrom([]byte(`{"status": "some status"}`)), + }, + } + + for idx, evt := range FixtureEventHistories { + if err := evt.Insert(ctx, db, boil.Infer()); err != nil { + errStr := fmt.Sprintf("event history %d", idx) + return errors.Wrap(err, errStr) + } + } + return nil +} + func setupConfigSet(ctx context.Context, db *sqlx.DB) error { settings := [][]*models.BiosConfigSetting{ { diff --git a/internal/models/boil_suites_test.go b/internal/models/boil_suites_test.go index 3683dac..14f2537 100644 --- a/internal/models/boil_suites_test.go +++ b/internal/models/boil_suites_test.go @@ -23,6 +23,7 @@ func TestParent(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSets) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMaps) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersions) + t.Run("EventHistories", testEventHistories) t.Run("ServerComponentTypes", testServerComponentTypes) t.Run("ServerComponents", testServerComponents) t.Run("ServerCredentialTypes", testServerCredentialTypes) @@ -55,6 +56,7 @@ func TestDelete(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsDelete) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsDelete) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsDelete) + t.Run("EventHistories", testEventHistoriesDelete) t.Run("ServerComponentTypes", testServerComponentTypesDelete) t.Run("ServerComponents", testServerComponentsDelete) t.Run("ServerCredentialTypes", testServerCredentialTypesDelete) @@ -75,6 +77,7 @@ func TestQueryDeleteAll(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsQueryDeleteAll) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsQueryDeleteAll) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsQueryDeleteAll) + t.Run("EventHistories", testEventHistoriesQueryDeleteAll) t.Run("ServerComponentTypes", testServerComponentTypesQueryDeleteAll) t.Run("ServerComponents", testServerComponentsQueryDeleteAll) t.Run("ServerCredentialTypes", testServerCredentialTypesQueryDeleteAll) @@ -95,6 +98,7 @@ func TestSliceDeleteAll(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsSliceDeleteAll) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsSliceDeleteAll) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsSliceDeleteAll) + t.Run("EventHistories", testEventHistoriesSliceDeleteAll) t.Run("ServerComponentTypes", testServerComponentTypesSliceDeleteAll) t.Run("ServerComponents", testServerComponentsSliceDeleteAll) t.Run("ServerCredentialTypes", testServerCredentialTypesSliceDeleteAll) @@ -115,6 +119,7 @@ func TestExists(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsExists) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsExists) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsExists) + t.Run("EventHistories", testEventHistoriesExists) t.Run("ServerComponentTypes", testServerComponentTypesExists) t.Run("ServerComponents", testServerComponentsExists) t.Run("ServerCredentialTypes", testServerCredentialTypesExists) @@ -135,6 +140,7 @@ func TestFind(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsFind) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsFind) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsFind) + t.Run("EventHistories", testEventHistoriesFind) t.Run("ServerComponentTypes", testServerComponentTypesFind) t.Run("ServerComponents", testServerComponentsFind) t.Run("ServerCredentialTypes", testServerCredentialTypesFind) @@ -155,6 +161,7 @@ func TestBind(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsBind) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsBind) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsBind) + t.Run("EventHistories", testEventHistoriesBind) t.Run("ServerComponentTypes", testServerComponentTypesBind) t.Run("ServerComponents", testServerComponentsBind) t.Run("ServerCredentialTypes", testServerCredentialTypesBind) @@ -175,6 +182,7 @@ func TestOne(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsOne) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsOne) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsOne) + t.Run("EventHistories", testEventHistoriesOne) t.Run("ServerComponentTypes", testServerComponentTypesOne) t.Run("ServerComponents", testServerComponentsOne) t.Run("ServerCredentialTypes", testServerCredentialTypesOne) @@ -195,6 +203,7 @@ func TestAll(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsAll) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsAll) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsAll) + t.Run("EventHistories", testEventHistoriesAll) t.Run("ServerComponentTypes", testServerComponentTypesAll) t.Run("ServerComponents", testServerComponentsAll) t.Run("ServerCredentialTypes", testServerCredentialTypesAll) @@ -215,6 +224,7 @@ func TestCount(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsCount) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsCount) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsCount) + t.Run("EventHistories", testEventHistoriesCount) t.Run("ServerComponentTypes", testServerComponentTypesCount) t.Run("ServerComponents", testServerComponentsCount) t.Run("ServerCredentialTypes", testServerCredentialTypesCount) @@ -235,6 +245,7 @@ func TestHooks(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsHooks) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsHooks) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsHooks) + t.Run("EventHistories", testEventHistoriesHooks) t.Run("ServerComponentTypes", testServerComponentTypesHooks) t.Run("ServerComponents", testServerComponentsHooks) t.Run("ServerCredentialTypes", testServerCredentialTypesHooks) @@ -266,6 +277,8 @@ func TestInsert(t *testing.T) { t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsInsertWhitelist) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsInsert) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsInsertWhitelist) + t.Run("EventHistories", testEventHistoriesInsert) + t.Run("EventHistories", testEventHistoriesInsertWhitelist) t.Run("ServerComponentTypes", testServerComponentTypesInsert) t.Run("ServerComponentTypes", testServerComponentTypesInsertWhitelist) t.Run("ServerComponents", testServerComponentsInsert) @@ -292,6 +305,7 @@ func TestToOne(t *testing.T) { t.Run("BMCMacAddressToBomInfoUsingSerialNumBomInfo", testBMCMacAddressToOneBomInfoUsingSerialNumBomInfo) t.Run("ComponentFirmwareSetMapToComponentFirmwareSetUsingFirmwareSet", testComponentFirmwareSetMapToOneComponentFirmwareSetUsingFirmwareSet) t.Run("ComponentFirmwareSetMapToComponentFirmwareVersionUsingFirmware", testComponentFirmwareSetMapToOneComponentFirmwareVersionUsingFirmware) + t.Run("EventHistoryToServerUsingTargetServerServer", testEventHistoryToOneServerUsingTargetServerServer) t.Run("ServerComponentToServerUsingServer", testServerComponentToOneServerUsingServer) t.Run("ServerComponentToServerComponentTypeUsingServerComponentType", testServerComponentToOneServerComponentTypeUsingServerComponentType) t.Run("ServerCredentialToServerCredentialTypeUsingServerCredentialType", testServerCredentialToOneServerCredentialTypeUsingServerCredentialType) @@ -319,6 +333,7 @@ func TestToMany(t *testing.T) { t.Run("ServerComponentToVersionedAttributes", testServerComponentToManyVersionedAttributes) t.Run("ServerCredentialTypeToServerCredentials", testServerCredentialTypeToManyServerCredentials) t.Run("ServerToAttributes", testServerToManyAttributes) + t.Run("ServerToTargetServerEventHistories", testServerToManyTargetServerEventHistories) t.Run("ServerToServerComponents", testServerToManyServerComponents) t.Run("ServerToServerCredentials", testServerToManyServerCredentials) t.Run("ServerToVersionedAttributes", testServerToManyVersionedAttributes) @@ -336,6 +351,7 @@ func TestToOneSet(t *testing.T) { t.Run("BMCMacAddressToBomInfoUsingSerialNumBMCMacAddresses", testBMCMacAddressToOneSetOpBomInfoUsingSerialNumBomInfo) t.Run("ComponentFirmwareSetMapToComponentFirmwareSetUsingFirmwareSetComponentFirmwareSetMaps", testComponentFirmwareSetMapToOneSetOpComponentFirmwareSetUsingFirmwareSet) t.Run("ComponentFirmwareSetMapToComponentFirmwareVersionUsingFirmwareComponentFirmwareSetMaps", testComponentFirmwareSetMapToOneSetOpComponentFirmwareVersionUsingFirmware) + t.Run("EventHistoryToServerUsingTargetServerEventHistories", testEventHistoryToOneSetOpServerUsingTargetServerServer) t.Run("ServerComponentToServerUsingServerComponents", testServerComponentToOneSetOpServerUsingServer) t.Run("ServerComponentToServerComponentTypeUsingServerComponents", testServerComponentToOneSetOpServerComponentTypeUsingServerComponentType) t.Run("ServerCredentialToServerCredentialTypeUsingServerCredentials", testServerCredentialToOneSetOpServerCredentialTypeUsingServerCredentialType) @@ -377,6 +393,7 @@ func TestToManyAdd(t *testing.T) { t.Run("ServerComponentToVersionedAttributes", testServerComponentToManyAddOpVersionedAttributes) t.Run("ServerCredentialTypeToServerCredentials", testServerCredentialTypeToManyAddOpServerCredentials) t.Run("ServerToAttributes", testServerToManyAddOpAttributes) + t.Run("ServerToTargetServerEventHistories", testServerToManyAddOpTargetServerEventHistories) t.Run("ServerToServerComponents", testServerToManyAddOpServerComponents) t.Run("ServerToServerCredentials", testServerToManyAddOpServerCredentials) t.Run("ServerToVersionedAttributes", testServerToManyAddOpVersionedAttributes) @@ -414,6 +431,7 @@ func TestReload(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsReload) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsReload) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsReload) + t.Run("EventHistories", testEventHistoriesReload) t.Run("ServerComponentTypes", testServerComponentTypesReload) t.Run("ServerComponents", testServerComponentsReload) t.Run("ServerCredentialTypes", testServerCredentialTypesReload) @@ -434,6 +452,7 @@ func TestReloadAll(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsReloadAll) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsReloadAll) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsReloadAll) + t.Run("EventHistories", testEventHistoriesReloadAll) t.Run("ServerComponentTypes", testServerComponentTypesReloadAll) t.Run("ServerComponents", testServerComponentsReloadAll) t.Run("ServerCredentialTypes", testServerCredentialTypesReloadAll) @@ -454,6 +473,7 @@ func TestSelect(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsSelect) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsSelect) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsSelect) + t.Run("EventHistories", testEventHistoriesSelect) t.Run("ServerComponentTypes", testServerComponentTypesSelect) t.Run("ServerComponents", testServerComponentsSelect) t.Run("ServerCredentialTypes", testServerCredentialTypesSelect) @@ -474,6 +494,7 @@ func TestUpdate(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsUpdate) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsUpdate) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsUpdate) + t.Run("EventHistories", testEventHistoriesUpdate) t.Run("ServerComponentTypes", testServerComponentTypesUpdate) t.Run("ServerComponents", testServerComponentsUpdate) t.Run("ServerCredentialTypes", testServerCredentialTypesUpdate) @@ -494,6 +515,7 @@ func TestSliceUpdateAll(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsSliceUpdateAll) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsSliceUpdateAll) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsSliceUpdateAll) + t.Run("EventHistories", testEventHistoriesSliceUpdateAll) t.Run("ServerComponentTypes", testServerComponentTypesSliceUpdateAll) t.Run("ServerComponents", testServerComponentsSliceUpdateAll) t.Run("ServerCredentialTypes", testServerCredentialTypesSliceUpdateAll) diff --git a/internal/models/boil_table_names.go b/internal/models/boil_table_names.go index 575087e..ec7ae29 100644 --- a/internal/models/boil_table_names.go +++ b/internal/models/boil_table_names.go @@ -15,6 +15,7 @@ var TableNames = struct { ComponentFirmwareSet string ComponentFirmwareSetMap string ComponentFirmwareVersion string + EventHistory string ServerComponentTypes string ServerComponents string ServerCredentialTypes string @@ -33,6 +34,7 @@ var TableNames = struct { ComponentFirmwareSet: "component_firmware_set", ComponentFirmwareSetMap: "component_firmware_set_map", ComponentFirmwareVersion: "component_firmware_version", + EventHistory: "event_history", ServerComponentTypes: "server_component_types", ServerComponents: "server_components", ServerCredentialTypes: "server_credential_types", diff --git a/internal/models/crdb_suites_test.go b/internal/models/crdb_suites_test.go index 0be24be..c2c5510 100644 --- a/internal/models/crdb_suites_test.go +++ b/internal/models/crdb_suites_test.go @@ -17,6 +17,7 @@ func TestUpsert(t *testing.T) { t.Run("ComponentFirmwareSets", testComponentFirmwareSetsUpsert) t.Run("ComponentFirmwareSetMaps", testComponentFirmwareSetMapsUpsert) t.Run("ComponentFirmwareVersions", testComponentFirmwareVersionsUpsert) + t.Run("EventHistories", testEventHistoriesUpsert) t.Run("ServerComponentTypes", testServerComponentTypesUpsert) t.Run("ServerComponents", testServerComponentsUpsert) t.Run("ServerCredentialTypes", testServerCredentialTypesUpsert) diff --git a/internal/models/event_history.go b/internal/models/event_history.go new file mode 100644 index 0000000..48d23e8 --- /dev/null +++ b/internal/models/event_history.go @@ -0,0 +1,1148 @@ +// Code generated by SQLBoiler 4.15.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "database/sql" + "fmt" + "reflect" + "strconv" + "strings" + "sync" + "time" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "github.com/volatiletech/sqlboiler/v4/queries/qmhelper" + "github.com/volatiletech/strmangle" +) + +// EventHistory is an object representing the database table. +type EventHistory struct { + EventID string `boil:"event_id" json:"event_id" toml:"event_id" yaml:"event_id"` + EventType string `boil:"event_type" json:"event_type" toml:"event_type" yaml:"event_type"` + EventStart time.Time `boil:"event_start" json:"event_start" toml:"event_start" yaml:"event_start"` + EventEnd time.Time `boil:"event_end" json:"event_end" toml:"event_end" yaml:"event_end"` + TargetServer string `boil:"target_server" json:"target_server" toml:"target_server" yaml:"target_server"` + Parameters null.JSON `boil:"parameters" json:"parameters,omitempty" toml:"parameters" yaml:"parameters,omitempty"` + FinalState string `boil:"final_state" json:"final_state" toml:"final_state" yaml:"final_state"` + FinalStatus null.JSON `boil:"final_status" json:"final_status,omitempty" toml:"final_status" yaml:"final_status,omitempty"` + + R *eventHistoryR `boil:"-" json:"-" toml:"-" yaml:"-"` + L eventHistoryL `boil:"-" json:"-" toml:"-" yaml:"-"` +} + +var EventHistoryColumns = struct { + EventID string + EventType string + EventStart string + EventEnd string + TargetServer string + Parameters string + FinalState string + FinalStatus string +}{ + EventID: "event_id", + EventType: "event_type", + EventStart: "event_start", + EventEnd: "event_end", + TargetServer: "target_server", + Parameters: "parameters", + FinalState: "final_state", + FinalStatus: "final_status", +} + +var EventHistoryTableColumns = struct { + EventID string + EventType string + EventStart string + EventEnd string + TargetServer string + Parameters string + FinalState string + FinalStatus string +}{ + EventID: "event_history.event_id", + EventType: "event_history.event_type", + EventStart: "event_history.event_start", + EventEnd: "event_history.event_end", + TargetServer: "event_history.target_server", + Parameters: "event_history.parameters", + FinalState: "event_history.final_state", + FinalStatus: "event_history.final_status", +} + +// Generated where + +type whereHelpertime_Time struct{ field string } + +func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.EQ, x) +} +func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.NEQ, x) +} +func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LT, x) +} +func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.LTE, x) +} +func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GT, x) +} +func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod { + return qmhelper.Where(w.field, qmhelper.GTE, x) +} + +var EventHistoryWhere = struct { + EventID whereHelperstring + EventType whereHelperstring + EventStart whereHelpertime_Time + EventEnd whereHelpertime_Time + TargetServer whereHelperstring + Parameters whereHelpernull_JSON + FinalState whereHelperstring + FinalStatus whereHelpernull_JSON +}{ + EventID: whereHelperstring{field: "\"event_history\".\"event_id\""}, + EventType: whereHelperstring{field: "\"event_history\".\"event_type\""}, + EventStart: whereHelpertime_Time{field: "\"event_history\".\"event_start\""}, + EventEnd: whereHelpertime_Time{field: "\"event_history\".\"event_end\""}, + TargetServer: whereHelperstring{field: "\"event_history\".\"target_server\""}, + Parameters: whereHelpernull_JSON{field: "\"event_history\".\"parameters\""}, + FinalState: whereHelperstring{field: "\"event_history\".\"final_state\""}, + FinalStatus: whereHelpernull_JSON{field: "\"event_history\".\"final_status\""}, +} + +// EventHistoryRels is where relationship names are stored. +var EventHistoryRels = struct { + TargetServerServer string +}{ + TargetServerServer: "TargetServerServer", +} + +// eventHistoryR is where relationships are stored. +type eventHistoryR struct { + TargetServerServer *Server `boil:"TargetServerServer" json:"TargetServerServer" toml:"TargetServerServer" yaml:"TargetServerServer"` +} + +// NewStruct creates a new relationship struct +func (*eventHistoryR) NewStruct() *eventHistoryR { + return &eventHistoryR{} +} + +func (r *eventHistoryR) GetTargetServerServer() *Server { + if r == nil { + return nil + } + return r.TargetServerServer +} + +// eventHistoryL is where Load methods for each relationship are stored. +type eventHistoryL struct{} + +var ( + eventHistoryAllColumns = []string{"event_id", "event_type", "event_start", "event_end", "target_server", "parameters", "final_state", "final_status"} + eventHistoryColumnsWithoutDefault = []string{"event_id", "event_type", "event_start", "event_end", "target_server", "final_state"} + eventHistoryColumnsWithDefault = []string{"parameters", "final_status"} + eventHistoryPrimaryKeyColumns = []string{"event_id"} + eventHistoryGeneratedColumns = []string{} +) + +type ( + // EventHistorySlice is an alias for a slice of pointers to EventHistory. + // This should almost always be used instead of []EventHistory. + EventHistorySlice []*EventHistory + // EventHistoryHook is the signature for custom EventHistory hook methods + EventHistoryHook func(context.Context, boil.ContextExecutor, *EventHistory) error + + eventHistoryQuery struct { + *queries.Query + } +) + +// Cache for insert, update and upsert +var ( + eventHistoryType = reflect.TypeOf(&EventHistory{}) + eventHistoryMapping = queries.MakeStructMapping(eventHistoryType) + eventHistoryPrimaryKeyMapping, _ = queries.BindMapping(eventHistoryType, eventHistoryMapping, eventHistoryPrimaryKeyColumns) + eventHistoryInsertCacheMut sync.RWMutex + eventHistoryInsertCache = make(map[string]insertCache) + eventHistoryUpdateCacheMut sync.RWMutex + eventHistoryUpdateCache = make(map[string]updateCache) + eventHistoryUpsertCacheMut sync.RWMutex + eventHistoryUpsertCache = make(map[string]insertCache) +) + +var ( + // Force time package dependency for automated UpdatedAt/CreatedAt. + _ = time.Second + // Force qmhelper dependency for where clause generation (which doesn't + // always happen) + _ = qmhelper.Where +) + +var eventHistoryAfterSelectHooks []EventHistoryHook + +var eventHistoryBeforeInsertHooks []EventHistoryHook +var eventHistoryAfterInsertHooks []EventHistoryHook + +var eventHistoryBeforeUpdateHooks []EventHistoryHook +var eventHistoryAfterUpdateHooks []EventHistoryHook + +var eventHistoryBeforeDeleteHooks []EventHistoryHook +var eventHistoryAfterDeleteHooks []EventHistoryHook + +var eventHistoryBeforeUpsertHooks []EventHistoryHook +var eventHistoryAfterUpsertHooks []EventHistoryHook + +// doAfterSelectHooks executes all "after Select" hooks. +func (o *EventHistory) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryAfterSelectHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeInsertHooks executes all "before insert" hooks. +func (o *EventHistory) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryBeforeInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterInsertHooks executes all "after Insert" hooks. +func (o *EventHistory) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryAfterInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpdateHooks executes all "before Update" hooks. +func (o *EventHistory) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryBeforeUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpdateHooks executes all "after Update" hooks. +func (o *EventHistory) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryAfterUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeDeleteHooks executes all "before Delete" hooks. +func (o *EventHistory) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryBeforeDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterDeleteHooks executes all "after Delete" hooks. +func (o *EventHistory) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryAfterDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpsertHooks executes all "before Upsert" hooks. +func (o *EventHistory) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryBeforeUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpsertHooks executes all "after Upsert" hooks. +func (o *EventHistory) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range eventHistoryAfterUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// AddEventHistoryHook registers your hook function for all future operations. +func AddEventHistoryHook(hookPoint boil.HookPoint, eventHistoryHook EventHistoryHook) { + switch hookPoint { + case boil.AfterSelectHook: + eventHistoryAfterSelectHooks = append(eventHistoryAfterSelectHooks, eventHistoryHook) + case boil.BeforeInsertHook: + eventHistoryBeforeInsertHooks = append(eventHistoryBeforeInsertHooks, eventHistoryHook) + case boil.AfterInsertHook: + eventHistoryAfterInsertHooks = append(eventHistoryAfterInsertHooks, eventHistoryHook) + case boil.BeforeUpdateHook: + eventHistoryBeforeUpdateHooks = append(eventHistoryBeforeUpdateHooks, eventHistoryHook) + case boil.AfterUpdateHook: + eventHistoryAfterUpdateHooks = append(eventHistoryAfterUpdateHooks, eventHistoryHook) + case boil.BeforeDeleteHook: + eventHistoryBeforeDeleteHooks = append(eventHistoryBeforeDeleteHooks, eventHistoryHook) + case boil.AfterDeleteHook: + eventHistoryAfterDeleteHooks = append(eventHistoryAfterDeleteHooks, eventHistoryHook) + case boil.BeforeUpsertHook: + eventHistoryBeforeUpsertHooks = append(eventHistoryBeforeUpsertHooks, eventHistoryHook) + case boil.AfterUpsertHook: + eventHistoryAfterUpsertHooks = append(eventHistoryAfterUpsertHooks, eventHistoryHook) + } +} + +// One returns a single eventHistory record from the query. +func (q eventHistoryQuery) One(ctx context.Context, exec boil.ContextExecutor) (*EventHistory, error) { + o := &EventHistory{} + + queries.SetLimit(q.Query, 1) + + err := q.Bind(ctx, exec, o) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: failed to execute a one query for event_history") + } + + if err := o.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + + return o, nil +} + +// All returns all EventHistory records from the query. +func (q eventHistoryQuery) All(ctx context.Context, exec boil.ContextExecutor) (EventHistorySlice, error) { + var o []*EventHistory + + err := q.Bind(ctx, exec, &o) + if err != nil { + return nil, errors.Wrap(err, "models: failed to assign all query results to EventHistory slice") + } + + if len(eventHistoryAfterSelectHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + } + } + + return o, nil +} + +// Count returns the count of all EventHistory records in the query. +func (q eventHistoryQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return 0, errors.Wrap(err, "models: failed to count event_history rows") + } + + return count, nil +} + +// Exists checks if the row exists in the table. +func (q eventHistoryQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + queries.SetLimit(q.Query, 1) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return false, errors.Wrap(err, "models: failed to check if event_history exists") + } + + return count > 0, nil +} + +// TargetServerServer pointed to by the foreign key. +func (o *EventHistory) TargetServerServer(mods ...qm.QueryMod) serverQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.TargetServer), + } + + queryMods = append(queryMods, mods...) + + return Servers(queryMods...) +} + +// LoadTargetServerServer allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (eventHistoryL) LoadTargetServerServer(ctx context.Context, e boil.ContextExecutor, singular bool, maybeEventHistory interface{}, mods queries.Applicator) error { + var slice []*EventHistory + var object *EventHistory + + if singular { + var ok bool + object, ok = maybeEventHistory.(*EventHistory) + if !ok { + object = new(EventHistory) + ok = queries.SetFromEmbeddedStruct(&object, &maybeEventHistory) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", object, maybeEventHistory)) + } + } + } else { + s, ok := maybeEventHistory.(*[]*EventHistory) + if ok { + slice = *s + } else { + ok = queries.SetFromEmbeddedStruct(&slice, maybeEventHistory) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", slice, maybeEventHistory)) + } + } + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &eventHistoryR{} + } + args = append(args, object.TargetServer) + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &eventHistoryR{} + } + + for _, a := range args { + if a == obj.TargetServer { + continue Outer + } + } + + args = append(args, obj.TargetServer) + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.From(`servers`), + qm.WhereIn(`servers.id in ?`, args...), + qmhelper.WhereIsNull(`servers.deleted_at`), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load Server") + } + + var resultSlice []*Server + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice Server") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for servers") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for servers") + } + + if len(serverAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.TargetServerServer = foreign + if foreign.R == nil { + foreign.R = &serverR{} + } + foreign.R.TargetServerEventHistories = append(foreign.R.TargetServerEventHistories, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if local.TargetServer == foreign.ID { + local.R.TargetServerServer = foreign + if foreign.R == nil { + foreign.R = &serverR{} + } + foreign.R.TargetServerEventHistories = append(foreign.R.TargetServerEventHistories, local) + break + } + } + } + + return nil +} + +// SetTargetServerServer of the eventHistory to the related item. +// Sets o.R.TargetServerServer to related. +// Adds o to related.R.TargetServerEventHistories. +func (o *EventHistory) SetTargetServerServer(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Server) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"event_history\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"target_server"}), + strmangle.WhereClause("\"", "\"", 2, eventHistoryPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.EventID} + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, updateQuery) + fmt.Fprintln(writer, values) + } + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + o.TargetServer = related.ID + if o.R == nil { + o.R = &eventHistoryR{ + TargetServerServer: related, + } + } else { + o.R.TargetServerServer = related + } + + if related.R == nil { + related.R = &serverR{ + TargetServerEventHistories: EventHistorySlice{o}, + } + } else { + related.R.TargetServerEventHistories = append(related.R.TargetServerEventHistories, o) + } + + return nil +} + +// EventHistories retrieves all the records using an executor. +func EventHistories(mods ...qm.QueryMod) eventHistoryQuery { + mods = append(mods, qm.From("\"event_history\"")) + q := NewQuery(mods...) + if len(queries.GetSelect(q)) == 0 { + queries.SetSelect(q, []string{"\"event_history\".*"}) + } + + return eventHistoryQuery{q} +} + +// FindEventHistory retrieves a single record by ID with an executor. +// If selectCols is empty Find will return all columns. +func FindEventHistory(ctx context.Context, exec boil.ContextExecutor, eventID string, selectCols ...string) (*EventHistory, error) { + eventHistoryObj := &EventHistory{} + + sel := "*" + if len(selectCols) > 0 { + sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") + } + query := fmt.Sprintf( + "select %s from \"event_history\" where \"event_id\"=$1", sel, + ) + + q := queries.Raw(query, eventID) + + err := q.Bind(ctx, exec, eventHistoryObj) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: unable to select from event_history") + } + + if err = eventHistoryObj.doAfterSelectHooks(ctx, exec); err != nil { + return eventHistoryObj, err + } + + return eventHistoryObj, nil +} + +// Insert a single record using an executor. +// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. +func (o *EventHistory) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { + if o == nil { + return errors.New("models: no event_history provided for insertion") + } + + var err error + + if err := o.doBeforeInsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(eventHistoryColumnsWithDefault, o) + + key := makeCacheKey(columns, nzDefaults) + eventHistoryInsertCacheMut.RLock() + cache, cached := eventHistoryInsertCache[key] + eventHistoryInsertCacheMut.RUnlock() + + if !cached { + wl, returnColumns := columns.InsertColumnSet( + eventHistoryAllColumns, + eventHistoryColumnsWithDefault, + eventHistoryColumnsWithoutDefault, + nzDefaults, + ) + + cache.valueMapping, err = queries.BindMapping(eventHistoryType, eventHistoryMapping, wl) + if err != nil { + return err + } + cache.retMapping, err = queries.BindMapping(eventHistoryType, eventHistoryMapping, returnColumns) + if err != nil { + return err + } + if len(wl) != 0 { + cache.query = fmt.Sprintf("INSERT INTO \"event_history\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) + } else { + cache.query = "INSERT INTO \"event_history\" %sDEFAULT VALUES%s" + } + + var queryOutput, queryReturning string + + if len(cache.retMapping) != 0 { + queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\"")) + } + + cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, vals) + } + + if len(cache.retMapping) != 0 { + err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) + } else { + _, err = exec.ExecContext(ctx, cache.query, vals...) + } + + if err != nil { + return errors.Wrap(err, "models: unable to insert into event_history") + } + + if !cached { + eventHistoryInsertCacheMut.Lock() + eventHistoryInsertCache[key] = cache + eventHistoryInsertCacheMut.Unlock() + } + + return o.doAfterInsertHooks(ctx, exec) +} + +// Update uses an executor to update the EventHistory. +// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates. +// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records. +func (o *EventHistory) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { + var err error + if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { + return 0, err + } + key := makeCacheKey(columns, nil) + eventHistoryUpdateCacheMut.RLock() + cache, cached := eventHistoryUpdateCache[key] + eventHistoryUpdateCacheMut.RUnlock() + + if !cached { + wl := columns.UpdateColumnSet( + eventHistoryAllColumns, + eventHistoryPrimaryKeyColumns, + ) + + if !columns.IsWhitelist() { + wl = strmangle.SetComplement(wl, []string{"created_at"}) + } + if len(wl) == 0 { + return 0, errors.New("models: unable to update event_history, could not build whitelist") + } + + cache.query = fmt.Sprintf("UPDATE \"event_history\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, wl), + strmangle.WhereClause("\"", "\"", len(wl)+1, eventHistoryPrimaryKeyColumns), + ) + cache.valueMapping, err = queries.BindMapping(eventHistoryType, eventHistoryMapping, append(wl, eventHistoryPrimaryKeyColumns...)) + if err != nil { + return 0, err + } + } + + values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, values) + } + var result sql.Result + result, err = exec.ExecContext(ctx, cache.query, values...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update event_history row") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by update for event_history") + } + + if !cached { + eventHistoryUpdateCacheMut.Lock() + eventHistoryUpdateCache[key] = cache + eventHistoryUpdateCacheMut.Unlock() + } + + return rowsAff, o.doAfterUpdateHooks(ctx, exec) +} + +// UpdateAll updates all rows with the specified column values. +func (q eventHistoryQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + queries.SetUpdate(q.Query, cols) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all for event_history") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected for event_history") + } + + return rowsAff, nil +} + +// UpdateAll updates all rows with the specified column values, using an executor. +func (o EventHistorySlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + ln := int64(len(o)) + if ln == 0 { + return 0, nil + } + + if len(cols) == 0 { + return 0, errors.New("models: update all requires at least one column argument") + } + + colNames := make([]string, len(cols)) + args := make([]interface{}, len(cols)) + + i := 0 + for name, value := range cols { + colNames[i] = name + args[i] = value + i++ + } + + // Append all of the primary key values for each column + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), eventHistoryPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := fmt.Sprintf("UPDATE \"event_history\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, colNames), + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, eventHistoryPrimaryKeyColumns, len(o))) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all in eventHistory slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all eventHistory") + } + return rowsAff, nil +} + +// Delete deletes a single EventHistory record with an executor. +// Delete will match against the primary key column to find the record to delete. +func (o *EventHistory) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if o == nil { + return 0, errors.New("models: no EventHistory provided for delete") + } + + if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), eventHistoryPrimaryKeyMapping) + sql := "DELETE FROM \"event_history\" WHERE \"event_id\"=$1" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete from event_history") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by delete for event_history") + } + + if err := o.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + return rowsAff, nil +} + +// DeleteAll deletes all matching rows. +func (q eventHistoryQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if q.Query == nil { + return 0, errors.New("models: no eventHistoryQuery provided for delete all") + } + + queries.SetDelete(q.Query) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from event_history") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for event_history") + } + + return rowsAff, nil +} + +// DeleteAll deletes all rows in the slice, using an executor. +func (o EventHistorySlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if len(o) == 0 { + return 0, nil + } + + if len(eventHistoryBeforeDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + var args []interface{} + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), eventHistoryPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "DELETE FROM \"event_history\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, eventHistoryPrimaryKeyColumns, len(o)) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from eventHistory slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for event_history") + } + + if len(eventHistoryAfterDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + return rowsAff, nil +} + +// Reload refetches the object from the database +// using the primary keys with an executor. +func (o *EventHistory) Reload(ctx context.Context, exec boil.ContextExecutor) error { + ret, err := FindEventHistory(ctx, exec, o.EventID) + if err != nil { + return err + } + + *o = *ret + return nil +} + +// ReloadAll refetches every row with matching primary key column values +// and overwrites the original object slice with the newly updated slice. +func (o *EventHistorySlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { + if o == nil || len(*o) == 0 { + return nil + } + + slice := EventHistorySlice{} + var args []interface{} + for _, obj := range *o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), eventHistoryPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "SELECT \"event_history\".* FROM \"event_history\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, eventHistoryPrimaryKeyColumns, len(*o)) + + q := queries.Raw(sql, args...) + + err := q.Bind(ctx, exec, &slice) + if err != nil { + return errors.Wrap(err, "models: unable to reload all in EventHistorySlice") + } + + *o = slice + + return nil +} + +// EventHistoryExists checks if the EventHistory row exists. +func EventHistoryExists(ctx context.Context, exec boil.ContextExecutor, eventID string) (bool, error) { + var exists bool + sql := "select exists(select 1 from \"event_history\" where \"event_id\"=$1 limit 1)" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, eventID) + } + row := exec.QueryRowContext(ctx, sql, eventID) + + err := row.Scan(&exists) + if err != nil { + return false, errors.Wrap(err, "models: unable to check if event_history exists") + } + + return exists, nil +} + +// Exists checks if the EventHistory row exists. +func (o *EventHistory) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { + return EventHistoryExists(ctx, exec, o.EventID) +} + +// Upsert attempts an insert using an executor, and does an update or ignore on conflict. +// See boil.Columns documentation for how to properly use updateColumns and insertColumns. +func (o *EventHistory) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) error { + if o == nil { + return errors.New("models: no event_history provided for upsert") + } + + if err := o.doBeforeUpsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(eventHistoryColumnsWithDefault, o) + + // Build cache key in-line uglily - mysql vs psql problems + buf := strmangle.GetBuffer() + if updateOnConflict { + buf.WriteByte('t') + } else { + buf.WriteByte('f') + } + buf.WriteByte('.') + for _, c := range conflictColumns { + buf.WriteString(c) + } + buf.WriteByte('.') + buf.WriteString(strconv.Itoa(updateColumns.Kind)) + for _, c := range updateColumns.Cols { + buf.WriteString(c) + } + buf.WriteByte('.') + buf.WriteString(strconv.Itoa(insertColumns.Kind)) + for _, c := range insertColumns.Cols { + buf.WriteString(c) + } + buf.WriteByte('.') + for _, c := range nzDefaults { + buf.WriteString(c) + } + key := buf.String() + strmangle.PutBuffer(buf) + + eventHistoryUpsertCacheMut.RLock() + cache, cached := eventHistoryUpsertCache[key] + eventHistoryUpsertCacheMut.RUnlock() + + var err error + + if !cached { + insert, ret := insertColumns.InsertColumnSet( + eventHistoryAllColumns, + eventHistoryColumnsWithDefault, + eventHistoryColumnsWithoutDefault, + nzDefaults, + ) + update := updateColumns.UpdateColumnSet( + eventHistoryAllColumns, + eventHistoryPrimaryKeyColumns, + ) + + if updateOnConflict && len(update) == 0 { + return errors.New("models: unable to upsert event_history, could not build update column list") + } + + conflict := conflictColumns + if len(conflict) == 0 { + conflict = make([]string, len(eventHistoryPrimaryKeyColumns)) + copy(conflict, eventHistoryPrimaryKeyColumns) + } + cache.query = buildUpsertQueryCockroachDB(dialect, "\"event_history\"", updateOnConflict, ret, update, conflict, insert) + + cache.valueMapping, err = queries.BindMapping(eventHistoryType, eventHistoryMapping, insert) + if err != nil { + return err + } + if len(ret) != 0 { + cache.retMapping, err = queries.BindMapping(eventHistoryType, eventHistoryMapping, ret) + if err != nil { + return err + } + } + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + var returns []interface{} + if len(cache.retMapping) != 0 { + returns = queries.PtrsFromMapping(value, cache.retMapping) + } + + if boil.DebugMode { + _, _ = fmt.Fprintln(boil.DebugWriter, cache.query) + _, _ = fmt.Fprintln(boil.DebugWriter, vals) + } + + if len(cache.retMapping) != 0 { + err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...) + if err == sql.ErrNoRows { + err = nil // CockcorachDB doesn't return anything when there's no update + } + } else { + _, err = exec.ExecContext(ctx, cache.query, vals...) + } + if err != nil { + return errors.Wrap(err, "models: unable to upsert event_history") + } + + if !cached { + eventHistoryUpsertCacheMut.Lock() + eventHistoryUpsertCache[key] = cache + eventHistoryUpsertCacheMut.Unlock() + } + + return o.doAfterUpsertHooks(ctx, exec) +} diff --git a/internal/models/event_history_test.go b/internal/models/event_history_test.go new file mode 100644 index 0000000..4927bf2 --- /dev/null +++ b/internal/models/event_history_test.go @@ -0,0 +1,851 @@ +// Code generated by SQLBoiler 4.15.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "bytes" + "context" + "reflect" + "testing" + + "github.com/volatiletech/randomize" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/strmangle" +) + +func testEventHistoriesUpsert(t *testing.T) { + t.Parallel() + + if len(eventHistoryAllColumns) == len(eventHistoryPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + // Attempt the INSERT side of an UPSERT + o := EventHistory{} + if err = randomize.Struct(seed, &o, eventHistoryDBTypes, true); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Upsert(ctx, tx, false, nil, boil.Infer(), boil.Infer()); err != nil { + t.Errorf("Unable to upsert EventHistory: %s", err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 1 { + t.Error("want one record, got:", count) + } + + // Attempt the UPDATE side of an UPSERT + if err = randomize.Struct(seed, &o, eventHistoryDBTypes, false, eventHistoryPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + if err = o.Upsert(ctx, tx, true, nil, boil.Infer(), boil.Infer()); err != nil { + t.Errorf("Unable to upsert EventHistory: %s", err) + } + + count, err = EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + if count != 1 { + t.Error("want one record, got:", count) + } +} + +var ( + // Relationships sometimes use the reflection helper queries.Equal/queries.Assign + // so force a package dependency in case they don't. + _ = queries.Equal +) + +func testEventHistories(t *testing.T) { + t.Parallel() + + query := EventHistories() + + if query.Query == nil { + t.Error("expected a query, got nothing") + } +} + +func testEventHistoriesDelete(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := o.Delete(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testEventHistoriesQueryDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if rowsAff, err := EventHistories().DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testEventHistoriesSliceDeleteAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := EventHistorySlice{o} + + if rowsAff, err := slice.DeleteAll(ctx, tx); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only have deleted one row, but affected:", rowsAff) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 0 { + t.Error("want zero records, got:", count) + } +} + +func testEventHistoriesExists(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + e, err := EventHistoryExists(ctx, tx, o.EventID) + if err != nil { + t.Errorf("Unable to check if EventHistory exists: %s", err) + } + if !e { + t.Errorf("Expected EventHistoryExists to return true, but got false.") + } +} + +func testEventHistoriesFind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + eventHistoryFound, err := FindEventHistory(ctx, tx, o.EventID) + if err != nil { + t.Error(err) + } + + if eventHistoryFound == nil { + t.Error("want a record, got nil") + } +} + +func testEventHistoriesBind(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = EventHistories().Bind(ctx, tx, o); err != nil { + t.Error(err) + } +} + +func testEventHistoriesOne(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if x, err := EventHistories().One(ctx, tx); err != nil { + t.Error(err) + } else if x == nil { + t.Error("expected to get a non nil record") + } +} + +func testEventHistoriesAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + eventHistoryOne := &EventHistory{} + eventHistoryTwo := &EventHistory{} + if err = randomize.Struct(seed, eventHistoryOne, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + if err = randomize.Struct(seed, eventHistoryTwo, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = eventHistoryOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = eventHistoryTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := EventHistories().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 2 { + t.Error("want 2 records, got:", len(slice)) + } +} + +func testEventHistoriesCount(t *testing.T) { + t.Parallel() + + var err error + seed := randomize.NewSeed() + eventHistoryOne := &EventHistory{} + eventHistoryTwo := &EventHistory{} + if err = randomize.Struct(seed, eventHistoryOne, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + if err = randomize.Struct(seed, eventHistoryTwo, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = eventHistoryOne.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + if err = eventHistoryTwo.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 2 { + t.Error("want 2 records, got:", count) + } +} + +func eventHistoryBeforeInsertHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryAfterInsertHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryAfterSelectHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryBeforeUpdateHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryAfterUpdateHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryBeforeDeleteHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryAfterDeleteHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryBeforeUpsertHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func eventHistoryAfterUpsertHook(ctx context.Context, e boil.ContextExecutor, o *EventHistory) error { + *o = EventHistory{} + return nil +} + +func testEventHistoriesHooks(t *testing.T) { + t.Parallel() + + var err error + + ctx := context.Background() + empty := &EventHistory{} + o := &EventHistory{} + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, o, eventHistoryDBTypes, false); err != nil { + t.Errorf("Unable to randomize EventHistory object: %s", err) + } + + AddEventHistoryHook(boil.BeforeInsertHook, eventHistoryBeforeInsertHook) + if err = o.doBeforeInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeInsertHook function to empty object, but got: %#v", o) + } + eventHistoryBeforeInsertHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.AfterInsertHook, eventHistoryAfterInsertHook) + if err = o.doAfterInsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterInsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterInsertHook function to empty object, but got: %#v", o) + } + eventHistoryAfterInsertHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.AfterSelectHook, eventHistoryAfterSelectHook) + if err = o.doAfterSelectHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterSelectHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterSelectHook function to empty object, but got: %#v", o) + } + eventHistoryAfterSelectHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.BeforeUpdateHook, eventHistoryBeforeUpdateHook) + if err = o.doBeforeUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpdateHook function to empty object, but got: %#v", o) + } + eventHistoryBeforeUpdateHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.AfterUpdateHook, eventHistoryAfterUpdateHook) + if err = o.doAfterUpdateHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpdateHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpdateHook function to empty object, but got: %#v", o) + } + eventHistoryAfterUpdateHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.BeforeDeleteHook, eventHistoryBeforeDeleteHook) + if err = o.doBeforeDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeDeleteHook function to empty object, but got: %#v", o) + } + eventHistoryBeforeDeleteHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.AfterDeleteHook, eventHistoryAfterDeleteHook) + if err = o.doAfterDeleteHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterDeleteHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterDeleteHook function to empty object, but got: %#v", o) + } + eventHistoryAfterDeleteHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.BeforeUpsertHook, eventHistoryBeforeUpsertHook) + if err = o.doBeforeUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected BeforeUpsertHook function to empty object, but got: %#v", o) + } + eventHistoryBeforeUpsertHooks = []EventHistoryHook{} + + AddEventHistoryHook(boil.AfterUpsertHook, eventHistoryAfterUpsertHook) + if err = o.doAfterUpsertHooks(ctx, nil); err != nil { + t.Errorf("Unable to execute doAfterUpsertHooks: %s", err) + } + if !reflect.DeepEqual(o, empty) { + t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o) + } + eventHistoryAfterUpsertHooks = []EventHistoryHook{} +} + +func testEventHistoriesInsert(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testEventHistoriesInsertWhitelist(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Whitelist(eventHistoryColumnsWithoutDefault...)); err != nil { + t.Error(err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } +} + +func testEventHistoryToOneServerUsingTargetServerServer(t *testing.T) { + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var local EventHistory + var foreign Server + + seed := randomize.NewSeed() + if err := randomize.Struct(seed, &local, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + if err := randomize.Struct(seed, &foreign, serverDBTypes, false, serverColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Server struct: %s", err) + } + + if err := foreign.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + local.TargetServer = foreign.ID + if err := local.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := local.TargetServerServer().One(ctx, tx) + if err != nil { + t.Fatal(err) + } + + if check.ID != foreign.ID { + t.Errorf("want: %v, got %v", foreign.ID, check.ID) + } + + ranAfterSelectHook := false + AddServerHook(boil.AfterSelectHook, func(ctx context.Context, e boil.ContextExecutor, o *Server) error { + ranAfterSelectHook = true + return nil + }) + + slice := EventHistorySlice{&local} + if err = local.L.LoadTargetServerServer(ctx, tx, false, (*[]*EventHistory)(&slice), nil); err != nil { + t.Fatal(err) + } + if local.R.TargetServerServer == nil { + t.Error("struct should have been eager loaded") + } + + local.R.TargetServerServer = nil + if err = local.L.LoadTargetServerServer(ctx, tx, true, &local, nil); err != nil { + t.Fatal(err) + } + if local.R.TargetServerServer == nil { + t.Error("struct should have been eager loaded") + } + + if !ranAfterSelectHook { + t.Error("failed to run AfterSelect hook for relationship") + } +} + +func testEventHistoryToOneSetOpServerUsingTargetServerServer(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a EventHistory + var b, c Server + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, eventHistoryDBTypes, false, strmangle.SetComplement(eventHistoryPrimaryKeyColumns, eventHistoryColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &b, serverDBTypes, false, strmangle.SetComplement(serverPrimaryKeyColumns, serverColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, serverDBTypes, false, strmangle.SetComplement(serverPrimaryKeyColumns, serverColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + for i, x := range []*Server{&b, &c} { + err = a.SetTargetServerServer(ctx, tx, i != 0, x) + if err != nil { + t.Fatal(err) + } + + if a.R.TargetServerServer != x { + t.Error("relationship struct not set to correct value") + } + + if x.R.TargetServerEventHistories[0] != &a { + t.Error("failed to append to foreign relationship struct") + } + if a.TargetServer != x.ID { + t.Error("foreign key was wrong value", a.TargetServer) + } + + zero := reflect.Zero(reflect.TypeOf(a.TargetServer)) + reflect.Indirect(reflect.ValueOf(&a.TargetServer)).Set(zero) + + if err = a.Reload(ctx, tx); err != nil { + t.Fatal("failed to reload", err) + } + + if a.TargetServer != x.ID { + t.Error("foreign key was wrong value", a.TargetServer, x.ID) + } + } +} + +func testEventHistoriesReload(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + if err = o.Reload(ctx, tx); err != nil { + t.Error(err) + } +} + +func testEventHistoriesReloadAll(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice := EventHistorySlice{o} + + if err = slice.ReloadAll(ctx, tx); err != nil { + t.Error(err) + } +} + +func testEventHistoriesSelect(t *testing.T) { + t.Parallel() + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + slice, err := EventHistories().All(ctx, tx) + if err != nil { + t.Error(err) + } + + if len(slice) != 1 { + t.Error("want one record, got:", len(slice)) + } +} + +var ( + eventHistoryDBTypes = map[string]string{`EventID`: `uuid`, `EventType`: `string`, `EventStart`: `timestamptz`, `EventEnd`: `timestamptz`, `TargetServer`: `uuid`, `Parameters`: `jsonb`, `FinalState`: `string`, `FinalStatus`: `jsonb`} + _ = bytes.MinRead +) + +func testEventHistoriesUpdate(t *testing.T) { + t.Parallel() + + if 0 == len(eventHistoryPrimaryKeyColumns) { + t.Skip("Skipping table with no primary key columns") + } + if len(eventHistoryAllColumns) == len(eventHistoryPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + if rowsAff, err := o.Update(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("should only affect one row but affected", rowsAff) + } +} + +func testEventHistoriesSliceUpdateAll(t *testing.T) { + t.Parallel() + + if len(eventHistoryAllColumns) == len(eventHistoryPrimaryKeyColumns) { + t.Skip("Skipping table with only primary key columns") + } + + seed := randomize.NewSeed() + var err error + o := &EventHistory{} + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + if err = o.Insert(ctx, tx, boil.Infer()); err != nil { + t.Error(err) + } + + count, err := EventHistories().Count(ctx, tx) + if err != nil { + t.Error(err) + } + + if count != 1 { + t.Error("want one record, got:", count) + } + + if err = randomize.Struct(seed, o, eventHistoryDBTypes, true, eventHistoryPrimaryKeyColumns...); err != nil { + t.Errorf("Unable to randomize EventHistory struct: %s", err) + } + + // Remove Primary keys and unique columns from what we plan to update + var fields []string + if strmangle.StringSliceMatch(eventHistoryAllColumns, eventHistoryPrimaryKeyColumns) { + fields = eventHistoryAllColumns + } else { + fields = strmangle.SetComplement( + eventHistoryAllColumns, + eventHistoryPrimaryKeyColumns, + ) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + typ := reflect.TypeOf(o).Elem() + n := typ.NumField() + + updateMap := M{} + for _, col := range fields { + for i := 0; i < n; i++ { + f := typ.Field(i) + if f.Tag.Get("boil") == col { + updateMap[col] = value.Field(i).Interface() + } + } + } + + slice := EventHistorySlice{o} + if rowsAff, err := slice.UpdateAll(ctx, tx, updateMap); err != nil { + t.Error(err) + } else if rowsAff != 1 { + t.Error("wanted one record updated but got", rowsAff) + } +} diff --git a/internal/models/server_components.go b/internal/models/server_components.go index b17e184..c9709a2 100644 --- a/internal/models/server_components.go +++ b/internal/models/server_components.go @@ -1434,7 +1434,7 @@ func (o *ServerComponent) Insert(ctx context.Context, exec boil.ContextExecutor, } if err != nil { - return err + return errors.Wrap(err, "models: unable to insert into server_components") } if !cached { diff --git a/internal/models/server_credential_types.go b/internal/models/server_credential_types.go index 7f446c5..6c2810a 100644 --- a/internal/models/server_credential_types.go +++ b/internal/models/server_credential_types.go @@ -68,27 +68,6 @@ var ServerCredentialTypeTableColumns = struct { // Generated where -type whereHelpertime_Time struct{ field string } - -func (w whereHelpertime_Time) EQ(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.EQ, x) -} -func (w whereHelpertime_Time) NEQ(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.NEQ, x) -} -func (w whereHelpertime_Time) LT(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LT, x) -} -func (w whereHelpertime_Time) LTE(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.LTE, x) -} -func (w whereHelpertime_Time) GT(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GT, x) -} -func (w whereHelpertime_Time) GTE(x time.Time) qm.QueryMod { - return qmhelper.Where(w.field, qmhelper.GTE, x) -} - var ServerCredentialTypeWhere = struct { ID whereHelperstring Name whereHelperstring diff --git a/internal/models/servers.go b/internal/models/servers.go index 0cbcbf8..2c2bcbf 100644 --- a/internal/models/servers.go +++ b/internal/models/servers.go @@ -87,23 +87,26 @@ var ServerWhere = struct { // ServerRels is where relationship names are stored. var ServerRels = struct { - Attributes string - ServerComponents string - ServerCredentials string - VersionedAttributes string + Attributes string + TargetServerEventHistories string + ServerComponents string + ServerCredentials string + VersionedAttributes string }{ - Attributes: "Attributes", - ServerComponents: "ServerComponents", - ServerCredentials: "ServerCredentials", - VersionedAttributes: "VersionedAttributes", + Attributes: "Attributes", + TargetServerEventHistories: "TargetServerEventHistories", + ServerComponents: "ServerComponents", + ServerCredentials: "ServerCredentials", + VersionedAttributes: "VersionedAttributes", } // serverR is where relationships are stored. type serverR struct { - Attributes AttributeSlice `boil:"Attributes" json:"Attributes" toml:"Attributes" yaml:"Attributes"` - ServerComponents ServerComponentSlice `boil:"ServerComponents" json:"ServerComponents" toml:"ServerComponents" yaml:"ServerComponents"` - ServerCredentials ServerCredentialSlice `boil:"ServerCredentials" json:"ServerCredentials" toml:"ServerCredentials" yaml:"ServerCredentials"` - VersionedAttributes VersionedAttributeSlice `boil:"VersionedAttributes" json:"VersionedAttributes" toml:"VersionedAttributes" yaml:"VersionedAttributes"` + Attributes AttributeSlice `boil:"Attributes" json:"Attributes" toml:"Attributes" yaml:"Attributes"` + TargetServerEventHistories EventHistorySlice `boil:"TargetServerEventHistories" json:"TargetServerEventHistories" toml:"TargetServerEventHistories" yaml:"TargetServerEventHistories"` + ServerComponents ServerComponentSlice `boil:"ServerComponents" json:"ServerComponents" toml:"ServerComponents" yaml:"ServerComponents"` + ServerCredentials ServerCredentialSlice `boil:"ServerCredentials" json:"ServerCredentials" toml:"ServerCredentials" yaml:"ServerCredentials"` + VersionedAttributes VersionedAttributeSlice `boil:"VersionedAttributes" json:"VersionedAttributes" toml:"VersionedAttributes" yaml:"VersionedAttributes"` } // NewStruct creates a new relationship struct @@ -118,6 +121,13 @@ func (r *serverR) GetAttributes() AttributeSlice { return r.Attributes } +func (r *serverR) GetTargetServerEventHistories() EventHistorySlice { + if r == nil { + return nil + } + return r.TargetServerEventHistories +} + func (r *serverR) GetServerComponents() ServerComponentSlice { if r == nil { return nil @@ -442,6 +452,20 @@ func (o *Server) Attributes(mods ...qm.QueryMod) attributeQuery { return Attributes(queryMods...) } +// TargetServerEventHistories retrieves all the event_history's EventHistories with an executor via target_server column. +func (o *Server) TargetServerEventHistories(mods ...qm.QueryMod) eventHistoryQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"event_history\".\"target_server\"=?", o.ID), + ) + + return EventHistories(queryMods...) +} + // ServerComponents retrieves all the server_component's ServerComponents with an executor. func (o *Server) ServerComponents(mods ...qm.QueryMod) serverComponentQuery { var queryMods []qm.QueryMod @@ -598,6 +622,120 @@ func (serverL) LoadAttributes(ctx context.Context, e boil.ContextExecutor, singu return nil } +// LoadTargetServerEventHistories allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (serverL) LoadTargetServerEventHistories(ctx context.Context, e boil.ContextExecutor, singular bool, maybeServer interface{}, mods queries.Applicator) error { + var slice []*Server + var object *Server + + if singular { + var ok bool + object, ok = maybeServer.(*Server) + if !ok { + object = new(Server) + ok = queries.SetFromEmbeddedStruct(&object, &maybeServer) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", object, maybeServer)) + } + } + } else { + s, ok := maybeServer.(*[]*Server) + if ok { + slice = *s + } else { + ok = queries.SetFromEmbeddedStruct(&slice, maybeServer) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", slice, maybeServer)) + } + } + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &serverR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &serverR{} + } + + for _, a := range args { + if a == obj.ID { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.From(`event_history`), + qm.WhereIn(`event_history.target_server in ?`, args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load event_history") + } + + var resultSlice []*EventHistory + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice event_history") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on event_history") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for event_history") + } + + if len(eventHistoryAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.TargetServerEventHistories = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &eventHistoryR{} + } + foreign.R.TargetServerServer = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if local.ID == foreign.TargetServer { + local.R.TargetServerEventHistories = append(local.R.TargetServerEventHistories, foreign) + if foreign.R == nil { + foreign.R = &eventHistoryR{} + } + foreign.R.TargetServerServer = local + break + } + } + } + + return nil +} + // LoadServerComponents allows an eager lookup of values, cached into the // loaded structs of the objects. This is for a 1-M or N-M relationship. func (serverL) LoadServerComponents(ctx context.Context, e boil.ContextExecutor, singular bool, maybeServer interface{}, mods queries.Applicator) error { @@ -1067,6 +1205,59 @@ func (o *Server) RemoveAttributes(ctx context.Context, exec boil.ContextExecutor return nil } +// AddTargetServerEventHistories adds the given related objects to the existing relationships +// of the server, optionally inserting them as new records. +// Appends related to o.R.TargetServerEventHistories. +// Sets related.R.TargetServerServer appropriately. +func (o *Server) AddTargetServerEventHistories(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*EventHistory) error { + var err error + for _, rel := range related { + if insert { + rel.TargetServer = o.ID + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"event_history\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"target_server"}), + strmangle.WhereClause("\"", "\"", 2, eventHistoryPrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.EventID} + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, updateQuery) + fmt.Fprintln(writer, values) + } + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + rel.TargetServer = o.ID + } + } + + if o.R == nil { + o.R = &serverR{ + TargetServerEventHistories: related, + } + } else { + o.R.TargetServerEventHistories = append(o.R.TargetServerEventHistories, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &eventHistoryR{ + TargetServerServer: o, + } + } else { + rel.R.TargetServerServer = o + } + } + return nil +} + // AddServerComponents adds the given related objects to the existing relationships // of the server, optionally inserting them as new records. // Appends related to o.R.ServerComponents. diff --git a/internal/models/servers_test.go b/internal/models/servers_test.go index 37c5c6e..4e33ca4 100644 --- a/internal/models/servers_test.go +++ b/internal/models/servers_test.go @@ -720,6 +720,84 @@ func testServerToManyAttributes(t *testing.T) { } } +func testServerToManyTargetServerEventHistories(t *testing.T) { + var err error + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Server + var b, c EventHistory + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, serverDBTypes, true, serverColumnsWithDefault...); err != nil { + t.Errorf("Unable to randomize Server struct: %s", err) + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + if err = randomize.Struct(seed, &b, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Fatal(err) + } + if err = randomize.Struct(seed, &c, eventHistoryDBTypes, false, eventHistoryColumnsWithDefault...); err != nil { + t.Fatal(err) + } + + b.TargetServer = a.ID + c.TargetServer = a.ID + + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + check, err := a.TargetServerEventHistories().All(ctx, tx) + if err != nil { + t.Fatal(err) + } + + bFound, cFound := false, false + for _, v := range check { + if v.TargetServer == b.TargetServer { + bFound = true + } + if v.TargetServer == c.TargetServer { + cFound = true + } + } + + if !bFound { + t.Error("expected to find b") + } + if !cFound { + t.Error("expected to find c") + } + + slice := ServerSlice{&a} + if err = a.L.LoadTargetServerEventHistories(ctx, tx, false, (*[]*Server)(&slice), nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.TargetServerEventHistories); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + a.R.TargetServerEventHistories = nil + if err = a.L.LoadTargetServerEventHistories(ctx, tx, true, &a, nil); err != nil { + t.Fatal(err) + } + if got := len(a.R.TargetServerEventHistories); got != 2 { + t.Error("number of eager loaded records wrong, got:", got) + } + + if t.Failed() { + t.Logf("%#v", check) + } +} + func testServerToManyServerComponents(t *testing.T) { var err error ctx := context.Background() @@ -1204,6 +1282,81 @@ func testServerToManyRemoveOpAttributes(t *testing.T) { } } +func testServerToManyAddOpTargetServerEventHistories(t *testing.T) { + var err error + + ctx := context.Background() + tx := MustTx(boil.BeginTx(ctx, nil)) + defer func() { _ = tx.Rollback() }() + + var a Server + var b, c, d, e EventHistory + + seed := randomize.NewSeed() + if err = randomize.Struct(seed, &a, serverDBTypes, false, strmangle.SetComplement(serverPrimaryKeyColumns, serverColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + foreigners := []*EventHistory{&b, &c, &d, &e} + for _, x := range foreigners { + if err = randomize.Struct(seed, x, eventHistoryDBTypes, false, strmangle.SetComplement(eventHistoryPrimaryKeyColumns, eventHistoryColumnsWithoutDefault)...); err != nil { + t.Fatal(err) + } + } + + if err := a.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = b.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + if err = c.Insert(ctx, tx, boil.Infer()); err != nil { + t.Fatal(err) + } + + foreignersSplitByInsertion := [][]*EventHistory{ + {&b, &c}, + {&d, &e}, + } + + for i, x := range foreignersSplitByInsertion { + err = a.AddTargetServerEventHistories(ctx, tx, i != 0, x...) + if err != nil { + t.Fatal(err) + } + + first := x[0] + second := x[1] + + if a.ID != first.TargetServer { + t.Error("foreign key was wrong value", a.ID, first.TargetServer) + } + if a.ID != second.TargetServer { + t.Error("foreign key was wrong value", a.ID, second.TargetServer) + } + + if first.R.TargetServerServer != &a { + t.Error("relationship was not added properly to the foreign slice") + } + if second.R.TargetServerServer != &a { + t.Error("relationship was not added properly to the foreign slice") + } + + if a.R.TargetServerEventHistories[i*2] != first { + t.Error("relationship struct slice not set to correct value") + } + if a.R.TargetServerEventHistories[i*2+1] != second { + t.Error("relationship struct slice not set to correct value") + } + + count, err := a.TargetServerEventHistories().Count(ctx, tx) + if err != nil { + t.Fatal(err) + } + if want := int64((i + 1) * 2); count != want { + t.Error("want", want, "got", count) + } + } +} func testServerToManyAddOpServerComponents(t *testing.T) { var err error diff --git a/pkg/api/v1/router.go b/pkg/api/v1/router.go index 7789abc..c464d51 100644 --- a/pkg/api/v1/router.go +++ b/pkg/api/v1/router.go @@ -145,6 +145,13 @@ func (r *Router) Routes(rg *gin.RouterGroup) { srvInventory.PUT("/:uuid", amw.AuthRequired(updateScopes("server")), r.setInventory) } + srvEvents := rg.Group("/events") + { + srvEvents.GET("/:evtID", amw.AuthRequired(readScopes("events")), r.getEventByID) + srvEvents.GET("/by-server/:srvID", amw.AuthRequired(readScopes("server")), r.getServerEvents) + srvEvents.PUT("/:evtID", amw.AuthRequired(updateScopes("events")), r.updateEvent) + } + // /server-bios-config-sets srvCfgSets := rg.Group("/server-bios-config-sets") { diff --git a/pkg/api/v1/router_events.go b/pkg/api/v1/router_events.go new file mode 100644 index 0000000..5094bb3 --- /dev/null +++ b/pkg/api/v1/router_events.go @@ -0,0 +1,283 @@ +package fleetdbapi + +import ( + "bytes" + "database/sql" + "encoding/json" + "fmt" + "time" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "go.uber.org/zap" + + "github.com/metal-toolbox/fleetdb/internal/metrics" + "github.com/metal-toolbox/fleetdb/internal/models" +) + +type Event struct { + EventID uuid.UUID `json:"event_id" binding:"required,uuid4_rfc4122"` + Type string `json:"event_type" binding:"required"` + Start time.Time `json:"event_start" binding:"required,ltfield=End"` + End time.Time `json:"event_end" binding:"required,gtfield=Start"` + Target uuid.UUID `json:"target_server" binding:"required,uuid4_rfc4122"` + Parameters json.RawMessage `json:"parameters,omitempty" binding:"-"` + FinalState string `json:"final_state" binding:"required"` + FinalStatus json.RawMessage `json:"final_status,omitempty" binding:"-"` +} + +func (r *Router) getEventByID(c *gin.Context) { + evtID, err := uuid.Parse(c.Param("evtID")) + if err != nil { + badRequestResponse(c, "failed to parse event id", err) + return + } + + eh, err := models.EventHistories( + models.EventHistoryWhere.EventID.EQ(evtID.String()), + ).One(c.Request.Context(), r.DB) + + switch { + case err == nil: + case errors.Is(err, sql.ErrNoRows): + msg := fmt.Sprintf("no event for id %s", evtID.String()) + notFoundResponse(c, msg) + return + default: + metrics.DBError("fetching event history") + r.Logger.With( + zap.Error(err), + zap.String("event_id", evtID.String()), + ).Warn("event history by id") + dbErrorResponse(c, err) + return + } + + evt := &Event{ + EventID: uuid.MustParse(eh.EventID), + Type: eh.EventType, + Start: eh.EventStart, + End: eh.EventEnd, + Target: uuid.MustParse(eh.TargetServer), + FinalState: eh.FinalState, + } + + if eh.Parameters.Valid { + evt.Parameters = eh.Parameters.JSON + } + + if eh.FinalStatus.Valid { + evt.FinalStatus = eh.FinalStatus.JSON + } + + itemResponse(c, evt) +} + +func (r *Router) getServerEvents(c *gin.Context) { + srvID, err := uuid.Parse(c.Param("srvID")) + if err != nil { + badRequestResponse(c, "failed to parse target server id", err) + return + } + + // parse pagination -- only honoring limit and page here + pageParams, err := parsePagination(c) + if err != nil { + badRequestResponse(c, "parsing pagination", err) + return + } + + limit := pageParams.Limit // default is 100 + if limit > 1000 { //nolint:gomnd // it's fine + limit = 1000 // more than 1000 event records in a single shot is sus + } + + var offset int + if pageParams.Page > 1 { // default page is 1 + offset = limit * (pageParams.Page - 1) + } + + // N.B. count returns 0, not sql.ErrNoRows + historyTotal, err := models.EventHistories( + models.EventHistoryWhere.TargetServer.EQ(srvID.String()), + ).Count(c.Request.Context(), r.DB) + + if err != nil { + r.Logger.With( + zap.Error(err), + zap.String("server_id", srvID.String()), + ).Warn("counting event history") + metrics.DBError("counting event history") + dbErrorResponse(c, err) + return + } + + if historyTotal == 0 { + msg := fmt.Sprintf("no events for server %s", srvID.String()) + notFoundResponse(c, msg) + return + } + + ehs, err := models.EventHistories( + models.EventHistoryWhere.TargetServer.EQ(srvID.String()), + qm.OrderBy("event_end DESC"), + qm.Limit(limit), + qm.Offset(offset), + ).All(c.Request.Context(), r.DB) + + if err != nil { + metrics.DBError("event history by server") + r.Logger.With( + zap.Error(err), + zap.String("target_id", srvID.String()), + ).Warn("fetching server event history") + dbErrorResponse(c, err) + return + } + + var evts []*Event + for _, eh := range ehs { + evt := &Event{ + EventID: uuid.MustParse(eh.EventID), + Type: eh.EventType, + Start: eh.EventStart, + End: eh.EventEnd, + Target: uuid.MustParse(eh.TargetServer), + FinalState: eh.FinalState, + } + + if eh.Parameters.Valid { + evt.Parameters = eh.Parameters.JSON + } + + if eh.FinalStatus.Valid { + evt.FinalStatus = eh.FinalStatus.JSON + } + + evts = append(evts, evt) + } + + pd := paginationData{ + pageCount: len(evts), + totalCount: historyTotal, + pager: pageParams, + } + listResponse(c, evts, pd) +} + +func equivalentEvents(evt *Event, eh *models.EventHistory) bool { + // test everything but the time + return evt.EventID.String() == eh.EventID && + evt.Target.String() == eh.TargetServer && + evt.Type == eh.EventType && + evt.FinalState == eh.FinalState && + bytes.Equal(evt.Parameters, eh.Parameters.JSON) && + bytes.Equal(evt.FinalStatus, eh.FinalStatus.JSON) +} + +func (r *Router) updateEvent(c *gin.Context) { + evtID, err := uuid.Parse(c.Param("evtID")) + if err != nil { + badRequestResponse(c, "failed to parse event id", err) + return + } + + evt := &Event{} + if err := c.ShouldBindJSON(evt); err != nil { + badRequestResponse(c, "invalid event payload", err) + return + } + + // initial sanity check + if evtID != evt.EventID { + badRequestResponse(c, "payload does not match presented id", nil) + } + + ctx := c.Request.Context() + // shortcut if we've seen this event before already + existing, err := models.EventHistories( + models.EventHistoryWhere.EventID.EQ(evt.EventID.String()), + ).One(ctx, r.DB) + + switch { + case errors.Is(err, sql.ErrNoRows): + case err == nil: + if equivalentEvents(evt, existing) { + createdResponse(c, existing.EventID) + return + } + badRequestResponse(c, fmt.Sprintf("id in use: %s", existing.EventID), errors.New("existing event")) + return + default: + metrics.DBError("fetching event history") + r.Logger.With( + zap.Error(err), + zap.String("event_id", evt.EventID.String()), + ).Warn("event history by id") + dbErrorResponse(c, err) + return + } + + eh := &models.EventHistory{ + EventID: evt.EventID.String(), + EventType: evt.Type, + EventStart: evt.Start, + EventEnd: evt.End, + TargetServer: evt.Target.String(), + Parameters: null.JSONFrom([]byte(evt.Parameters)), + FinalState: evt.FinalState, + FinalStatus: null.JSONFrom([]byte(evt.FinalStatus)), + } + + txn, err := r.DB.Begin() + if err != nil { + r.Logger.With( + zap.Error(err), + zap.String("event_id", evt.EventID.String()), + ).Warn("unable to create transaction") + metrics.DBError("creating transaction") + dbErrorResponse(c, err) + return + } + + doRollback := false + rollbackFn := func() { + if doRollback { + if rbErr := txn.Rollback(); rbErr != nil { + r.Logger.With( + zap.Error(rbErr), + ).Warn("rollback error on event insertion") + metrics.DBError("rollback event insertion") + } + } + } + defer rollbackFn() + + if err := eh.Insert(c.Request.Context(), txn, boil.Infer()); err != nil { + doRollback = true + r.Logger.With( + zap.Error(err), + zap.String("event_id", evt.EventID.String()), + ).Warn("failed inserting event history") + badRequestResponse(c, "failed inserting event", errors.Wrap(err, + fmt.Sprintf("event %s", evt.EventID.String()))) + return + } + + if err := txn.Commit(); err != nil { + doRollback = true + r.Logger.With( + zap.Error(err), + zap.String("event_id", evt.EventID.String()), + ).Warn("unable to commit transaction") + metrics.DBError("commit event transaction") + dbErrorResponse(c, err) + return + } + + createdResponse(c, evt.EventID.String()) +} diff --git a/pkg/api/v1/router_events_test.go b/pkg/api/v1/router_events_test.go new file mode 100644 index 0000000..4a74ef3 --- /dev/null +++ b/pkg/api/v1/router_events_test.go @@ -0,0 +1,96 @@ +package fleetdbapi_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + "github.com/metal-toolbox/fleetdb/internal/dbtools" + fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" +) + +func TestGetEventByID(t *testing.T) { + s := serverTest(t) + realClientTests(t, func(ctx context.Context, authToken string, respCode int, expectError bool) error { + s.Client.SetToken(authToken) + + evtID := uuid.MustParse(dbtools.FixtureEventHistories[0].EventID) + evt, _, err := s.Client.GetEventByID(ctx, evtID) + if !expectError { + // we should get back the fixture data for the inventory server + // we don't care about the name of the server + require.NoError(t, err) + require.NotNil(t, evt) + require.Equal(t, dbtools.FixtureEventHistoryServer.ID, evt.Target.String()) + require.Equal(t, "succeeded", evt.FinalState) + } + return err + }) + + // event id not found + bogus := uuid.New() + _, _, err := s.Client.GetEventByID(context.Background(), bogus) + se := &fleetdbapi.ServerError{} + require.ErrorAs(t, err, se) + expStr := fmt.Sprintf("no event for id %s", bogus.String()) + require.Equal(t, 404, se.StatusCode) + require.Equal(t, expStr, se.Message) +} + +func TestGetServerEvents(t *testing.T) { + s := serverTest(t) + realClientTests(t, func(ctx context.Context, auth string, code int, expErr bool) error { + s.Client.SetToken(auth) + srvID := uuid.MustParse(dbtools.FixtureEventHistoryServer.ID) + evts, _, err := s.Client.GetServerEvents(ctx, srvID, nil) + if !expErr { + require.NoError(t, err) + require.Equal(t, 3, len(evts)) + } + return err + }) + bogus := uuid.New() + _, _, err := s.Client.GetServerEvents(context.Background(), bogus, &fleetdbapi.PaginationParams{}) + se := &fleetdbapi.ServerError{} + require.ErrorAs(t, err, se) + expStr := fmt.Sprintf("no events for server %s", bogus.String()) + require.Equal(t, 404, se.StatusCode) + require.Equal(t, expStr, se.Message) +} + +func TestUpdateEvent(t *testing.T) { + s := serverTest(t) + evt := &fleetdbapi.Event{ + EventID: uuid.New(), + Type: "test event 2", + Start: time.Now().Add(-1 * time.Minute), + End: time.Now().Add(-30 * time.Second), + Target: uuid.MustParse(dbtools.FixtureEventHistoryServer.ID), + FinalState: "succeeded", + } + realClientTests(t, func(ctx context.Context, auth string, code int, expErr bool) error { + s.Client.SetToken(auth) + r, err := s.Client.UpdateEvent(ctx, evt) + if !expErr { + require.NoError(t, err) + require.Equal(t, evt.EventID.String(), r.Slug) + } + return err + }) + // repeat with the same payload, get the same result + r, err := s.Client.UpdateEvent(context.Background(), evt) + require.NoError(t, err) + require.Equal(t, evt.EventID.String(), r.Slug) + // change the payload, get an error + evt.FinalState = "failed" + r, err = s.Client.UpdateEvent(context.Background(), evt) + se := &fleetdbapi.ServerError{} + require.ErrorAs(t, err, se) + expStr := fmt.Sprintf("id in use: %s", evt.EventID.String()) + require.Equal(t, 400, se.StatusCode) + require.Equal(t, expStr, se.Message) +} diff --git a/pkg/api/v1/router_int_test.go b/pkg/api/v1/router_int_test.go index e8f4d31..4ee781c 100644 --- a/pkg/api/v1/router_int_test.go +++ b/pkg/api/v1/router_int_test.go @@ -28,7 +28,7 @@ func serverTest(t *testing.T) *integrationServer { db := dbtools.DatabaseTest(t) - l := zap.NewNop() + l, _ := zap.NewDevelopment() hs := httpsrv.Server{ Logger: l, diff --git a/pkg/api/v1/router_server_components_test.go b/pkg/api/v1/router_server_components_test.go index a2723f9..3f3f8fc 100644 --- a/pkg/api/v1/router_server_components_test.go +++ b/pkg/api/v1/router_server_components_test.go @@ -256,7 +256,7 @@ func TestIntegrationServerGetComponents(t *testing.T) { { "component Versioned Attributes is returned as expected", servers[1].UUID, - 3, + 1, fleetdbapi.ServerComponent{ ServerUUID: servers[1].UUID, Name: "My Lucky Fin", diff --git a/pkg/api/v1/router_server_test.go b/pkg/api/v1/router_server_test.go index a3c101f..44caf12 100644 --- a/pkg/api/v1/router_server_test.go +++ b/pkg/api/v1/router_server_test.go @@ -24,11 +24,11 @@ func TestIntegrationServerList(t *testing.T) { r, resp, err := s.Client.List(ctx, nil) if !expectError { require.NoError(t, err) - assert.Len(t, r, 4) + assert.Len(t, r, 5) - assert.EqualValues(t, 4, resp.PageCount) + assert.EqualValues(t, 5, resp.PageCount) assert.EqualValues(t, 1, resp.TotalPages) - assert.EqualValues(t, 4, resp.TotalRecordCount) + assert.EqualValues(t, 5, resp.TotalRecordCount) // We returned everything, so we shouldnt have a next page info assert.Nil(t, resp.Links.Next) assert.Nil(t, resp.Links.Previous) @@ -144,7 +144,13 @@ func TestIntegrationServerList(t *testing.T) { { "empty search filter", nil, - []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, + []string{ + dbtools.FixtureEventHistoryServer.ID, + dbtools.FixtureInventoryServer.ID, + dbtools.FixtureNemo.ID, + dbtools.FixtureDory.ID, + dbtools.FixtureMarlin.ID, + }, false, "", }, @@ -436,14 +442,27 @@ func TestIntegrationServerList(t *testing.T) { { "search for server without IncludeDeleted defined", &fleetdbapi.ServerListParams{}, - []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, + []string{ + dbtools.FixtureEventHistoryServer.ID, + dbtools.FixtureInventoryServer.ID, + dbtools.FixtureNemo.ID, + dbtools.FixtureDory.ID, + dbtools.FixtureMarlin.ID, + }, false, "", }, { "search for server with IncludeDeleted defined", &fleetdbapi.ServerListParams{IncludeDeleted: true}, - []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID, dbtools.FixtureChuckles.ID}, + []string{ + dbtools.FixtureEventHistoryServer.ID, + dbtools.FixtureInventoryServer.ID, + dbtools.FixtureNemo.ID, + dbtools.FixtureDory.ID, + dbtools.FixtureMarlin.ID, + dbtools.FixtureChuckles.ID, + }, false, "", }, @@ -515,8 +534,8 @@ func TestIntegrationServerListPagination(t *testing.T) { assert.Len(t, r, 2) assert.EqualValues(t, 2, resp.PageCount) - assert.EqualValues(t, 2, resp.TotalPages) - assert.EqualValues(t, 4, resp.TotalRecordCount) + assert.EqualValues(t, 3, resp.TotalPages) + assert.EqualValues(t, 5, resp.TotalRecordCount) // Since we have a next page let's make sure all the links are set assert.NotNil(t, resp.Links.Next) assert.Nil(t, resp.Links.Previous) @@ -532,11 +551,16 @@ func TestIntegrationServerListPagination(t *testing.T) { assert.EqualValues(t, 2, resp.PageCount) + // get the last page + resp, err = s.Client.NextPage(context.TODO(), *resp, &r) + assert.NoError(t, err) + assert.Len(t, r, 1) + // we should have followed the cursor so first/previous/next/last links shouldn't be set // but there is another page so we should have a next cursor link. Total counts are not includes // cursor pages - assert.EqualValues(t, 2, resp.TotalPages) - assert.EqualValues(t, 4, resp.TotalRecordCount) + assert.EqualValues(t, 3, resp.TotalPages) + assert.EqualValues(t, 5, resp.TotalRecordCount) assert.NotNil(t, resp.Links.First) assert.NotNil(t, resp.Links.Previous) assert.Nil(t, resp.Links.Next) diff --git a/pkg/api/v1/server_service.go b/pkg/api/v1/server_service.go index a41a124..6dd7ea1 100644 --- a/pkg/api/v1/server_service.go +++ b/pkg/api/v1/server_service.go @@ -76,6 +76,10 @@ type ClientInterface interface { GetServerInventory(context.Context, uuid.UUID, bool) (*rivets.Server, *ServerResponse, error) SetServerInventory(context.Context, uuid.UUID, *rivets.Server, bool) (*ServerResponse, error) + GetEventByID(context.Context, uuid.UUID) (*Event, *ServerResponse, error) + GetServerEvents(context.Context, uuid.UUID) ([]*Event, *ServerResponse, error) + UpdateEvent(context.Context, *Event) (*ServerResponse, error) + CreateServerBiosConfigSet(context.Context, BiosConfigSet) (*uuid.UUID, *ServerResponse, error) GetServerBiosConfigSet(context.Context, uuid.UUID) (*BiosConfigSet, *ServerResponse, error) DeleteServerBiosConfigSet(context.Context, uuid.UUID) (*ServerResponse, error) @@ -484,6 +488,39 @@ func (c *Client) SetServerInventory(ctx context.Context, srvID uuid.UUID, return c.put(ctx, path, srv) } +// GetEventByID returns the details of the event with the given ID +func (c *Client) GetEventByID(ctx context.Context, evtID uuid.UUID) (*Event, *ServerResponse, error) { + evt := &Event{} + r := &ServerResponse{Record: evt} + path := fmt.Sprintf("events/%s", evtID.String()) + + if err := c.get(ctx, path, r); err != nil { + return nil, nil, err + } + + return evt, r, nil +} + +// GetServerEvents returns the most recent events for the given server ID +func (c *Client) GetServerEvents(ctx context.Context, srvID uuid.UUID, + params *PaginationParams) ([]*Event, *ServerResponse, error) { + evts := &[]*Event{} + r := &ServerResponse{Records: evts} + path := fmt.Sprintf("events/by-server/%s", srvID.String()) + + if err := c.list(ctx, path, params, r); err != nil { + return nil, nil, err + } + + return *evts, r, nil +} + +// UpdateEvent adds a new event to the event history +func (c *Client) UpdateEvent(ctx context.Context, evt *Event) (*ServerResponse, error) { + path := fmt.Sprintf("events/%s", evt.EventID.String()) + return c.put(ctx, path, evt) +} + // CreateServerBiosConfigSet will store the BiosConfigSet, and return the generated UUID of the BiosConfigSet func (c *Client) CreateServerBiosConfigSet(ctx context.Context, set BiosConfigSet) (*ServerResponse, error) { resp, err := c.post(ctx, serverBiosConfigSetEndpoint, set)