diff --git a/backend/app/api/handlers/v1/v1_ctrl_maintenance_plan.go b/backend/app/api/handlers/v1/v1_ctrl_maintenance_plan.go new file mode 100644 index 000000000..9b4b999e0 --- /dev/null +++ b/backend/app/api/handlers/v1/v1_ctrl_maintenance_plan.go @@ -0,0 +1,85 @@ +package v1 + +import ( + "net/http" + + "github.com/google/uuid" + "github.com/hay-kot/httpkit/errchain" + "github.com/sysadminsmedia/homebox/backend/internal/core/services" + "github.com/sysadminsmedia/homebox/backend/internal/data/repo" + "github.com/sysadminsmedia/homebox/backend/internal/web/adapters" +) + +// HandleMaintenancePlanGetAll godoc +// +// @Summary Query Maintenance Plans +// @Tags Item Maintenance +// @Produce json +// @Param id path string true "Item ID" +// @Success 200 {array} repo.MaintenancePlan +// @Router /v1/entities/{id}/maintenance/plans [GET] +// @Security Bearer +func (ctrl *V1Controller) HandleMaintenancePlanGetAll() errchain.HandlerFunc { + fn := func(r *http.Request, itemID uuid.UUID, _ struct{}) ([]repo.MaintenancePlan, error) { + auth := services.NewContext(r.Context()) + return ctrl.repo.MaintEntry.ListPlansByItemID(auth, auth.GID, itemID) + } + + return adapters.QueryID("id", fn, http.StatusOK) +} + +// HandleMaintenancePlanCreate godoc +// +// @Summary Create Maintenance Plan +// @Tags Item Maintenance +// @Produce json +// @Param id path string true "Item ID" +// @Param payload body repo.MaintenancePlanCreate true "Plan Data" +// @Success 201 {object} repo.MaintenancePlan +// @Router /v1/entities/{id}/maintenance/plans [POST] +// @Security Bearer +func (ctrl *V1Controller) HandleMaintenancePlanCreate() errchain.HandlerFunc { + fn := func(r *http.Request, itemID uuid.UUID, body repo.MaintenancePlanCreate) (repo.MaintenancePlan, error) { + auth := services.NewContext(r.Context()) + return ctrl.repo.MaintEntry.CreatePlan(auth, itemID, body) + } + + return adapters.ActionID("id", fn, http.StatusCreated) +} + +// HandleMaintenancePlanUpdate godoc +// +// @Summary Update Maintenance Plan +// @Tags Maintenance +// @Produce json +// @Param id path string true "Plan ID" +// @Param payload body repo.MaintenancePlanUpdate true "Plan Data" +// @Success 200 {object} repo.MaintenancePlan +// @Router /v1/maintenance/plans/{id} [PUT] +// @Security Bearer +func (ctrl *V1Controller) HandleMaintenancePlanUpdate() errchain.HandlerFunc { + fn := func(r *http.Request, planID uuid.UUID, body repo.MaintenancePlanUpdate) (repo.MaintenancePlan, error) { + auth := services.NewContext(r.Context()) + return ctrl.repo.MaintEntry.UpdatePlan(auth, planID, body) + } + + return adapters.ActionID("id", fn, http.StatusOK) +} + +// HandleMaintenancePlanDelete godoc +// +// @Summary Delete Maintenance Plan +// @Tags Maintenance +// @Produce json +// @Param id path string true "Plan ID" +// @Success 204 +// @Router /v1/maintenance/plans/{id} [DELETE] +// @Security Bearer +func (ctrl *V1Controller) HandleMaintenancePlanDelete() errchain.HandlerFunc { + fn := func(r *http.Request, planID uuid.UUID) (any, error) { + auth := services.NewContext(r.Context()) + return nil, ctrl.repo.MaintEntry.DeletePlan(auth, planID) + } + + return adapters.CommandID("id", fn, http.StatusNoContent) +} diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 218546751..16fb557ca 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -194,6 +194,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR // Entity maintenance endpoints r.Get("/entities/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceLogGet(), userMW...)) r.Post("/entities/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryCreate(), userMW...)) + r.Get("/entities/{id}/maintenance/plans", chain.ToHandlerFunc(v1Ctrl.HandleMaintenancePlanGetAll(), userMW...)) + r.Post("/entities/{id}/maintenance/plans", chain.ToHandlerFunc(v1Ctrl.HandleMaintenancePlanCreate(), userMW...)) r.Get("/assets/{id}", chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...)) @@ -209,6 +211,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR r.Get("/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceGetAll(), userMW...)) r.Put("/maintenance/{id}", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryUpdate(), userMW...)) r.Delete("/maintenance/{id}", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryDelete(), userMW...)) + r.Put("/maintenance/plans/{id}", chain.ToHandlerFunc(v1Ctrl.HandleMaintenancePlanUpdate(), userMW...)) + r.Delete("/maintenance/plans/{id}", chain.ToHandlerFunc(v1Ctrl.HandleMaintenancePlanDelete(), userMW...)) // Notifiers r.Get("/notifiers", chain.ToHandlerFunc(v1Ctrl.HandleGetUserNotifiers(), userMW...)) diff --git a/backend/go.sum b/backend/go.sum index 782bb6012..a29fef7e1 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -143,12 +143,6 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo= -github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= -github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= @@ -390,14 +384,6 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI= github.com/olahol/melody v1.4.0/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= -github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= -github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= -github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= -github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= -github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 h1:jrYnow5+hy3WRDCBypUFvVKNSPPCdqgSXIE9eJDD8LM= -github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew= -github.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA= -github.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= @@ -445,10 +431,6 @@ github.com/shirou/gopsutil/v4 v4.26.4 h1:B4SXVbcwTyrocPHEmWBC4uCYr4Xcu3MK1TXqbpr github.com/shirou/gopsutil/v4 v4.26.4/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/backend/internal/data/ent/client.go b/backend/internal/data/ent/client.go index 8d7d57c0f..55279909b 100644 --- a/backend/internal/data/ent/client.go +++ b/backend/internal/data/ent/client.go @@ -28,6 +28,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/groupinvitationtoken" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/notifier" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/passwordresettokens" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" @@ -65,6 +66,8 @@ type Client struct { GroupInvitationToken *GroupInvitationTokenClient // MaintenanceEntry is the client for interacting with the MaintenanceEntry builders. MaintenanceEntry *MaintenanceEntryClient + // MaintenancePlan is the client for interacting with the MaintenancePlan builders. + MaintenancePlan *MaintenancePlanClient // Notifier is the client for interacting with the Notifier builders. Notifier *NotifierClient // PasswordResetTokens is the client for interacting with the PasswordResetTokens builders. @@ -100,6 +103,7 @@ func (c *Client) init() { c.Group = NewGroupClient(c.config) c.GroupInvitationToken = NewGroupInvitationTokenClient(c.config) c.MaintenanceEntry = NewMaintenanceEntryClient(c.config) + c.MaintenancePlan = NewMaintenancePlanClient(c.config) c.Notifier = NewNotifierClient(c.config) c.PasswordResetTokens = NewPasswordResetTokensClient(c.config) c.Tag = NewTagClient(c.config) @@ -210,6 +214,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Group: NewGroupClient(cfg), GroupInvitationToken: NewGroupInvitationTokenClient(cfg), MaintenanceEntry: NewMaintenanceEntryClient(cfg), + MaintenancePlan: NewMaintenancePlanClient(cfg), Notifier: NewNotifierClient(cfg), PasswordResetTokens: NewPasswordResetTokensClient(cfg), Tag: NewTagClient(cfg), @@ -247,6 +252,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Group: NewGroupClient(cfg), GroupInvitationToken: NewGroupInvitationTokenClient(cfg), MaintenanceEntry: NewMaintenanceEntryClient(cfg), + MaintenancePlan: NewMaintenancePlanClient(cfg), Notifier: NewNotifierClient(cfg), PasswordResetTokens: NewPasswordResetTokensClient(cfg), Tag: NewTagClient(cfg), @@ -284,8 +290,8 @@ func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ c.APIKey, c.Attachment, c.AuthRoles, c.AuthTokens, c.Entity, c.EntityField, c.EntityTemplate, c.EntityType, c.Export, c.Group, c.GroupInvitationToken, - c.MaintenanceEntry, c.Notifier, c.PasswordResetTokens, c.Tag, c.TemplateField, - c.User, c.UserGroup, + c.MaintenanceEntry, c.MaintenancePlan, c.Notifier, c.PasswordResetTokens, c.Tag, + c.TemplateField, c.User, c.UserGroup, } { n.Use(hooks...) } @@ -297,8 +303,8 @@ func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ c.APIKey, c.Attachment, c.AuthRoles, c.AuthTokens, c.Entity, c.EntityField, c.EntityTemplate, c.EntityType, c.Export, c.Group, c.GroupInvitationToken, - c.MaintenanceEntry, c.Notifier, c.PasswordResetTokens, c.Tag, c.TemplateField, - c.User, c.UserGroup, + c.MaintenanceEntry, c.MaintenancePlan, c.Notifier, c.PasswordResetTokens, c.Tag, + c.TemplateField, c.User, c.UserGroup, } { n.Intercept(interceptors...) } @@ -331,6 +337,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.GroupInvitationToken.mutate(ctx, m) case *MaintenanceEntryMutation: return c.MaintenanceEntry.mutate(ctx, m) + case *MaintenancePlanMutation: + return c.MaintenancePlan.mutate(ctx, m) case *NotifierMutation: return c.Notifier.mutate(ctx, m) case *PasswordResetTokensMutation: @@ -1196,6 +1204,22 @@ func (c *EntityClient) QueryMaintenanceEntries(_m *Entity) *MaintenanceEntryQuer return query } +// QueryMaintenancePlans queries the maintenance_plans edge of a Entity. +func (c *EntityClient) QueryMaintenancePlans(_m *Entity) *MaintenancePlanQuery { + query := (&MaintenancePlanClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(entity.Table, entity.FieldID, id), + sqlgraph.To(maintenanceplan.Table, maintenanceplan.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, entity.MaintenancePlansTable, entity.MaintenancePlansColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + // QueryAttachments queries the attachments edge of a Entity. func (c *EntityClient) QueryAttachments(_m *Entity) *AttachmentQuery { query := (&AttachmentClient{config: c.config}).Query() @@ -2447,6 +2471,22 @@ func (c *MaintenanceEntryClient) QueryEntity(_m *MaintenanceEntry) *EntityQuery return query } +// QueryPlan queries the plan edge of a MaintenanceEntry. +func (c *MaintenanceEntryClient) QueryPlan(_m *MaintenanceEntry) *MaintenancePlanQuery { + query := (&MaintenancePlanClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceentry.Table, maintenanceentry.FieldID, id), + sqlgraph.To(maintenanceplan.Table, maintenanceplan.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, maintenanceentry.PlanTable, maintenanceentry.PlanColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *MaintenanceEntryClient) Hooks() []Hook { return c.hooks.MaintenanceEntry @@ -2472,6 +2512,171 @@ func (c *MaintenanceEntryClient) mutate(ctx context.Context, m *MaintenanceEntry } } +// MaintenancePlanClient is a client for the MaintenancePlan schema. +type MaintenancePlanClient struct { + config +} + +// NewMaintenancePlanClient returns a client for the MaintenancePlan from the given config. +func NewMaintenancePlanClient(c config) *MaintenancePlanClient { + return &MaintenancePlanClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `maintenanceplan.Hooks(f(g(h())))`. +func (c *MaintenancePlanClient) Use(hooks ...Hook) { + c.hooks.MaintenancePlan = append(c.hooks.MaintenancePlan, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `maintenanceplan.Intercept(f(g(h())))`. +func (c *MaintenancePlanClient) Intercept(interceptors ...Interceptor) { + c.inters.MaintenancePlan = append(c.inters.MaintenancePlan, interceptors...) +} + +// Create returns a builder for creating a MaintenancePlan entity. +func (c *MaintenancePlanClient) Create() *MaintenancePlanCreate { + mutation := newMaintenancePlanMutation(c.config, OpCreate) + return &MaintenancePlanCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of MaintenancePlan entities. +func (c *MaintenancePlanClient) CreateBulk(builders ...*MaintenancePlanCreate) *MaintenancePlanCreateBulk { + return &MaintenancePlanCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *MaintenancePlanClient) MapCreateBulk(slice any, setFunc func(*MaintenancePlanCreate, int)) *MaintenancePlanCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &MaintenancePlanCreateBulk{err: fmt.Errorf("calling to MaintenancePlanClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*MaintenancePlanCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &MaintenancePlanCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for MaintenancePlan. +func (c *MaintenancePlanClient) Update() *MaintenancePlanUpdate { + mutation := newMaintenancePlanMutation(c.config, OpUpdate) + return &MaintenancePlanUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *MaintenancePlanClient) UpdateOne(_m *MaintenancePlan) *MaintenancePlanUpdateOne { + mutation := newMaintenancePlanMutation(c.config, OpUpdateOne, withMaintenancePlan(_m)) + return &MaintenancePlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *MaintenancePlanClient) UpdateOneID(id uuid.UUID) *MaintenancePlanUpdateOne { + mutation := newMaintenancePlanMutation(c.config, OpUpdateOne, withMaintenancePlanID(id)) + return &MaintenancePlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for MaintenancePlan. +func (c *MaintenancePlanClient) Delete() *MaintenancePlanDelete { + mutation := newMaintenancePlanMutation(c.config, OpDelete) + return &MaintenancePlanDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *MaintenancePlanClient) DeleteOne(_m *MaintenancePlan) *MaintenancePlanDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *MaintenancePlanClient) DeleteOneID(id uuid.UUID) *MaintenancePlanDeleteOne { + builder := c.Delete().Where(maintenanceplan.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &MaintenancePlanDeleteOne{builder} +} + +// Query returns a query builder for MaintenancePlan. +func (c *MaintenancePlanClient) Query() *MaintenancePlanQuery { + return &MaintenancePlanQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeMaintenancePlan}, + inters: c.Interceptors(), + } +} + +// Get returns a MaintenancePlan entity by its id. +func (c *MaintenancePlanClient) Get(ctx context.Context, id uuid.UUID) (*MaintenancePlan, error) { + return c.Query().Where(maintenanceplan.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *MaintenancePlanClient) GetX(ctx context.Context, id uuid.UUID) *MaintenancePlan { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryEntity queries the entity edge of a MaintenancePlan. +func (c *MaintenancePlanClient) QueryEntity(_m *MaintenancePlan) *EntityQuery { + query := (&EntityClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceplan.Table, maintenanceplan.FieldID, id), + sqlgraph.To(entity.Table, entity.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, maintenanceplan.EntityTable, maintenanceplan.EntityColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryMaintenanceEntries queries the maintenance_entries edge of a MaintenancePlan. +func (c *MaintenancePlanClient) QueryMaintenanceEntries(_m *MaintenancePlan) *MaintenanceEntryQuery { + query := (&MaintenanceEntryClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceplan.Table, maintenanceplan.FieldID, id), + sqlgraph.To(maintenanceentry.Table, maintenanceentry.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, maintenanceplan.MaintenanceEntriesTable, maintenanceplan.MaintenanceEntriesColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *MaintenancePlanClient) Hooks() []Hook { + return c.hooks.MaintenancePlan +} + +// Interceptors returns the client interceptors. +func (c *MaintenancePlanClient) Interceptors() []Interceptor { + return c.inters.MaintenancePlan +} + +func (c *MaintenancePlanClient) mutate(ctx context.Context, m *MaintenancePlanMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&MaintenancePlanCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&MaintenancePlanUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&MaintenancePlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&MaintenancePlanDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown MaintenancePlan mutation op: %q", m.Op()) + } +} + // NotifierClient is a client for the Notifier schema. type NotifierClient struct { config @@ -3481,12 +3686,12 @@ func (c *UserGroupClient) mutate(ctx context.Context, m *UserGroupMutation) (Val type ( hooks struct { APIKey, Attachment, AuthRoles, AuthTokens, Entity, EntityField, EntityTemplate, - EntityType, Export, Group, GroupInvitationToken, MaintenanceEntry, Notifier, - PasswordResetTokens, Tag, TemplateField, User, UserGroup []ent.Hook + EntityType, Export, Group, GroupInvitationToken, MaintenanceEntry, MaintenancePlan, + Notifier, PasswordResetTokens, Tag, TemplateField, User, UserGroup []ent.Hook } inters struct { APIKey, Attachment, AuthRoles, AuthTokens, Entity, EntityField, EntityTemplate, - EntityType, Export, Group, GroupInvitationToken, MaintenanceEntry, Notifier, - PasswordResetTokens, Tag, TemplateField, User, UserGroup []ent.Interceptor + EntityType, Export, Group, GroupInvitationToken, MaintenanceEntry, MaintenancePlan, + Notifier, PasswordResetTokens, Tag, TemplateField, User, UserGroup []ent.Interceptor } ) diff --git a/backend/internal/data/ent/ent.go b/backend/internal/data/ent/ent.go index 8539764b8..0de23bf77 100644 --- a/backend/internal/data/ent/ent.go +++ b/backend/internal/data/ent/ent.go @@ -24,6 +24,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/groupinvitationtoken" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/notifier" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/passwordresettokens" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" @@ -102,6 +103,7 @@ func checkColumn(t, c string) error { group.Table: group.ValidColumn, groupinvitationtoken.Table: groupinvitationtoken.ValidColumn, maintenanceentry.Table: maintenanceentry.ValidColumn, + maintenanceplan.Table: maintenanceplan.ValidColumn, notifier.Table: notifier.ValidColumn, passwordresettokens.Table: passwordresettokens.ValidColumn, tag.Table: tag.ValidColumn, diff --git a/backend/internal/data/ent/entity.go b/backend/internal/data/ent/entity.go index 7de031330..3be1f4bef 100644 --- a/backend/internal/data/ent/entity.go +++ b/backend/internal/data/ent/entity.go @@ -93,11 +93,13 @@ type EntityEdges struct { Fields []*EntityField `json:"fields,omitempty"` // MaintenanceEntries holds the value of the maintenance_entries edge. MaintenanceEntries []*MaintenanceEntry `json:"maintenance_entries,omitempty"` + // MaintenancePlans holds the value of the maintenance_plans edge. + MaintenancePlans []*MaintenancePlan `json:"maintenance_plans,omitempty"` // Attachments holds the value of the attachments edge. Attachments []*Attachment `json:"attachments,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [8]bool + loadedTypes [9]bool } // GroupOrErr returns the Group value or an error if the edge @@ -169,10 +171,19 @@ func (e EntityEdges) MaintenanceEntriesOrErr() ([]*MaintenanceEntry, error) { return nil, &NotLoadedError{edge: "maintenance_entries"} } +// MaintenancePlansOrErr returns the MaintenancePlans value or an error if the edge +// was not loaded in eager-loading. +func (e EntityEdges) MaintenancePlansOrErr() ([]*MaintenancePlan, error) { + if e.loadedTypes[7] { + return e.MaintenancePlans, nil + } + return nil, &NotLoadedError{edge: "maintenance_plans"} +} + // AttachmentsOrErr returns the Attachments value or an error if the edge // was not loaded in eager-loading. func (e EntityEdges) AttachmentsOrErr() ([]*Attachment, error) { - if e.loadedTypes[7] { + if e.loadedTypes[8] { return e.Attachments, nil } return nil, &NotLoadedError{edge: "attachments"} @@ -435,6 +446,11 @@ func (_m *Entity) QueryMaintenanceEntries() *MaintenanceEntryQuery { return NewEntityClient(_m.config).QueryMaintenanceEntries(_m) } +// QueryMaintenancePlans queries the "maintenance_plans" edge of the Entity entity. +func (_m *Entity) QueryMaintenancePlans() *MaintenancePlanQuery { + return NewEntityClient(_m.config).QueryMaintenancePlans(_m) +} + // QueryAttachments queries the "attachments" edge of the Entity entity. func (_m *Entity) QueryAttachments() *AttachmentQuery { return NewEntityClient(_m.config).QueryAttachments(_m) diff --git a/backend/internal/data/ent/entity/entity.go b/backend/internal/data/ent/entity/entity.go index 86695dcb5..890822aff 100644 --- a/backend/internal/data/ent/entity/entity.go +++ b/backend/internal/data/ent/entity/entity.go @@ -77,6 +77,8 @@ const ( EdgeFields = "fields" // EdgeMaintenanceEntries holds the string denoting the maintenance_entries edge name in mutations. EdgeMaintenanceEntries = "maintenance_entries" + // EdgeMaintenancePlans holds the string denoting the maintenance_plans edge name in mutations. + EdgeMaintenancePlans = "maintenance_plans" // EdgeAttachments holds the string denoting the attachments edge name in mutations. EdgeAttachments = "attachments" // Table holds the table name of the entity in the database. @@ -122,6 +124,13 @@ const ( MaintenanceEntriesInverseTable = "maintenance_entries" // MaintenanceEntriesColumn is the table column denoting the maintenance_entries relation/edge. MaintenanceEntriesColumn = "entity_id" + // MaintenancePlansTable is the table that holds the maintenance_plans relation/edge. + MaintenancePlansTable = "maintenance_plans" + // MaintenancePlansInverseTable is the table name for the MaintenancePlan entity. + // It exists in this package in order to avoid circular dependency with the "maintenanceplan" package. + MaintenancePlansInverseTable = "maintenance_plans" + // MaintenancePlansColumn is the table column denoting the maintenance_plans relation/edge. + MaintenancePlansColumn = "entity_id" // AttachmentsTable is the table that holds the attachments relation/edge. AttachmentsTable = "attachments" // AttachmentsInverseTable is the table name for the Attachment entity. @@ -439,6 +448,20 @@ func ByMaintenanceEntries(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOptio } } +// ByMaintenancePlansCount orders the results by maintenance_plans count. +func ByMaintenancePlansCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMaintenancePlansStep(), opts...) + } +} + +// ByMaintenancePlans orders the results by maintenance_plans terms. +func ByMaintenancePlans(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMaintenancePlansStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} + // ByAttachmentsCount orders the results by attachments count. func ByAttachmentsCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { @@ -501,6 +524,13 @@ func newMaintenanceEntriesStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, MaintenanceEntriesTable, MaintenanceEntriesColumn), ) } +func newMaintenancePlansStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MaintenancePlansInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, MaintenancePlansTable, MaintenancePlansColumn), + ) +} func newAttachmentsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), diff --git a/backend/internal/data/ent/entity/where.go b/backend/internal/data/ent/entity/where.go index 2115f63ff..97d96acf4 100644 --- a/backend/internal/data/ent/entity/where.go +++ b/backend/internal/data/ent/entity/where.go @@ -1582,6 +1582,29 @@ func HasMaintenanceEntriesWith(preds ...predicate.MaintenanceEntry) predicate.En }) } +// HasMaintenancePlans applies the HasEdge predicate on the "maintenance_plans" edge. +func HasMaintenancePlans() predicate.Entity { + return predicate.Entity(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, MaintenancePlansTable, MaintenancePlansColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMaintenancePlansWith applies the HasEdge predicate on the "maintenance_plans" edge with a given conditions (other predicates). +func HasMaintenancePlansWith(preds ...predicate.MaintenancePlan) predicate.Entity { + return predicate.Entity(func(s *sql.Selector) { + step := newMaintenancePlansStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // HasAttachments applies the HasEdge predicate on the "attachments" edge. func HasAttachments() predicate.Entity { return predicate.Entity(func(s *sql.Selector) { diff --git a/backend/internal/data/ent/entity_create.go b/backend/internal/data/ent/entity_create.go index fdf2917bf..376716361 100644 --- a/backend/internal/data/ent/entity_create.go +++ b/backend/internal/data/ent/entity_create.go @@ -17,6 +17,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entitytype" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" ) @@ -470,6 +471,21 @@ func (_c *EntityCreate) AddMaintenanceEntries(v ...*MaintenanceEntry) *EntityCre return _c.AddMaintenanceEntryIDs(ids...) } +// AddMaintenancePlanIDs adds the "maintenance_plans" edge to the MaintenancePlan entity by IDs. +func (_c *EntityCreate) AddMaintenancePlanIDs(ids ...uuid.UUID) *EntityCreate { + _c.mutation.AddMaintenancePlanIDs(ids...) + return _c +} + +// AddMaintenancePlans adds the "maintenance_plans" edges to the MaintenancePlan entity. +func (_c *EntityCreate) AddMaintenancePlans(v ...*MaintenancePlan) *EntityCreate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddMaintenancePlanIDs(ids...) +} + // AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs. func (_c *EntityCreate) AddAttachmentIDs(ids ...uuid.UUID) *EntityCreate { _c.mutation.AddAttachmentIDs(ids...) @@ -898,6 +914,22 @@ func (_c *EntityCreate) createSpec() (*Entity, *sqlgraph.CreateSpec) { } _spec.Edges = append(_spec.Edges, edge) } + if nodes := _c.mutation.MaintenancePlansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } if nodes := _c.mutation.AttachmentsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/backend/internal/data/ent/entity_query.go b/backend/internal/data/ent/entity_query.go index 775a6401e..61ef5a1e2 100644 --- a/backend/internal/data/ent/entity_query.go +++ b/backend/internal/data/ent/entity_query.go @@ -19,6 +19,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entitytype" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" ) @@ -37,6 +38,7 @@ type EntityQuery struct { withEntityType *EntityTypeQuery withFields *EntityFieldQuery withMaintenanceEntries *MaintenanceEntryQuery + withMaintenancePlans *MaintenancePlanQuery withAttachments *AttachmentQuery withFKs bool // intermediate query (i.e. traversal path). @@ -229,6 +231,28 @@ func (_q *EntityQuery) QueryMaintenanceEntries() *MaintenanceEntryQuery { return query } +// QueryMaintenancePlans chains the current query on the "maintenance_plans" edge. +func (_q *EntityQuery) QueryMaintenancePlans() *MaintenancePlanQuery { + query := (&MaintenancePlanClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(entity.Table, entity.FieldID, selector), + sqlgraph.To(maintenanceplan.Table, maintenanceplan.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, entity.MaintenancePlansTable, entity.MaintenancePlansColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + // QueryAttachments chains the current query on the "attachments" edge. func (_q *EntityQuery) QueryAttachments() *AttachmentQuery { query := (&AttachmentClient{config: _q.config}).Query() @@ -450,6 +474,7 @@ func (_q *EntityQuery) Clone() *EntityQuery { withEntityType: _q.withEntityType.Clone(), withFields: _q.withFields.Clone(), withMaintenanceEntries: _q.withMaintenanceEntries.Clone(), + withMaintenancePlans: _q.withMaintenancePlans.Clone(), withAttachments: _q.withAttachments.Clone(), // clone intermediate query. sql: _q.sql.Clone(), @@ -534,6 +559,17 @@ func (_q *EntityQuery) WithMaintenanceEntries(opts ...func(*MaintenanceEntryQuer return _q } +// WithMaintenancePlans tells the query-builder to eager-load the nodes that are connected to +// the "maintenance_plans" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *EntityQuery) WithMaintenancePlans(opts ...func(*MaintenancePlanQuery)) *EntityQuery { + query := (&MaintenancePlanClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMaintenancePlans = query + return _q +} + // WithAttachments tells the query-builder to eager-load the nodes that are connected to // the "attachments" edge. The optional arguments are used to configure the query builder of the edge. func (_q *EntityQuery) WithAttachments(opts ...func(*AttachmentQuery)) *EntityQuery { @@ -624,7 +660,7 @@ func (_q *EntityQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Entit nodes = []*Entity{} withFKs = _q.withFKs _spec = _q.querySpec() - loadedTypes = [8]bool{ + loadedTypes = [9]bool{ _q.withGroup != nil, _q.withParent != nil, _q.withChildren != nil, @@ -632,6 +668,7 @@ func (_q *EntityQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Entit _q.withEntityType != nil, _q.withFields != nil, _q.withMaintenanceEntries != nil, + _q.withMaintenancePlans != nil, _q.withAttachments != nil, } ) @@ -707,6 +744,13 @@ func (_q *EntityQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Entit return nil, err } } + if query := _q.withMaintenancePlans; query != nil { + if err := _q.loadMaintenancePlans(ctx, query, nodes, + func(n *Entity) { n.Edges.MaintenancePlans = []*MaintenancePlan{} }, + func(n *Entity, e *MaintenancePlan) { n.Edges.MaintenancePlans = append(n.Edges.MaintenancePlans, e) }); err != nil { + return nil, err + } + } if query := _q.withAttachments; query != nil { if err := _q.loadAttachments(ctx, query, nodes, func(n *Entity) { n.Edges.Attachments = []*Attachment{} }, @@ -966,6 +1010,36 @@ func (_q *EntityQuery) loadMaintenanceEntries(ctx context.Context, query *Mainte } return nil } +func (_q *EntityQuery) loadMaintenancePlans(ctx context.Context, query *MaintenancePlanQuery, nodes []*Entity, init func(*Entity), assign func(*Entity, *MaintenancePlan)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[uuid.UUID]*Entity) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(maintenanceplan.FieldEntityID) + } + query.Where(predicate.MaintenancePlan(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(entity.MaintenancePlansColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.EntityID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "entity_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} func (_q *EntityQuery) loadAttachments(ctx context.Context, query *AttachmentQuery, nodes []*Entity, init func(*Entity), assign func(*Entity, *Attachment)) error { fks := make([]driver.Value, 0, len(nodes)) nodeids := make(map[uuid.UUID]*Entity) diff --git a/backend/internal/data/ent/entity_update.go b/backend/internal/data/ent/entity_update.go index f3dbf1f4f..64d2e3d39 100644 --- a/backend/internal/data/ent/entity_update.go +++ b/backend/internal/data/ent/entity_update.go @@ -18,6 +18,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entitytype" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" ) @@ -556,6 +557,21 @@ func (_u *EntityUpdate) AddMaintenanceEntries(v ...*MaintenanceEntry) *EntityUpd return _u.AddMaintenanceEntryIDs(ids...) } +// AddMaintenancePlanIDs adds the "maintenance_plans" edge to the MaintenancePlan entity by IDs. +func (_u *EntityUpdate) AddMaintenancePlanIDs(ids ...uuid.UUID) *EntityUpdate { + _u.mutation.AddMaintenancePlanIDs(ids...) + return _u +} + +// AddMaintenancePlans adds the "maintenance_plans" edges to the MaintenancePlan entity. +func (_u *EntityUpdate) AddMaintenancePlans(v ...*MaintenancePlan) *EntityUpdate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMaintenancePlanIDs(ids...) +} + // AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs. func (_u *EntityUpdate) AddAttachmentIDs(ids ...uuid.UUID) *EntityUpdate { _u.mutation.AddAttachmentIDs(ids...) @@ -678,6 +694,27 @@ func (_u *EntityUpdate) RemoveMaintenanceEntries(v ...*MaintenanceEntry) *Entity return _u.RemoveMaintenanceEntryIDs(ids...) } +// ClearMaintenancePlans clears all "maintenance_plans" edges to the MaintenancePlan entity. +func (_u *EntityUpdate) ClearMaintenancePlans() *EntityUpdate { + _u.mutation.ClearMaintenancePlans() + return _u +} + +// RemoveMaintenancePlanIDs removes the "maintenance_plans" edge to MaintenancePlan entities by IDs. +func (_u *EntityUpdate) RemoveMaintenancePlanIDs(ids ...uuid.UUID) *EntityUpdate { + _u.mutation.RemoveMaintenancePlanIDs(ids...) + return _u +} + +// RemoveMaintenancePlans removes "maintenance_plans" edges to MaintenancePlan entities. +func (_u *EntityUpdate) RemoveMaintenancePlans(v ...*MaintenancePlan) *EntityUpdate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMaintenancePlanIDs(ids...) +} + // ClearAttachments clears all "attachments" edges to the Attachment entity. func (_u *EntityUpdate) ClearAttachments() *EntityUpdate { _u.mutation.ClearAttachments() @@ -1190,6 +1227,51 @@ func (_u *EntityUpdate) sqlSave(ctx context.Context) (_node int, err error) { } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.MaintenancePlansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMaintenancePlansIDs(); len(nodes) > 0 && !_u.mutation.MaintenancePlansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MaintenancePlansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if _u.mutation.AttachmentsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -1776,6 +1858,21 @@ func (_u *EntityUpdateOne) AddMaintenanceEntries(v ...*MaintenanceEntry) *Entity return _u.AddMaintenanceEntryIDs(ids...) } +// AddMaintenancePlanIDs adds the "maintenance_plans" edge to the MaintenancePlan entity by IDs. +func (_u *EntityUpdateOne) AddMaintenancePlanIDs(ids ...uuid.UUID) *EntityUpdateOne { + _u.mutation.AddMaintenancePlanIDs(ids...) + return _u +} + +// AddMaintenancePlans adds the "maintenance_plans" edges to the MaintenancePlan entity. +func (_u *EntityUpdateOne) AddMaintenancePlans(v ...*MaintenancePlan) *EntityUpdateOne { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMaintenancePlanIDs(ids...) +} + // AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs. func (_u *EntityUpdateOne) AddAttachmentIDs(ids ...uuid.UUID) *EntityUpdateOne { _u.mutation.AddAttachmentIDs(ids...) @@ -1898,6 +1995,27 @@ func (_u *EntityUpdateOne) RemoveMaintenanceEntries(v ...*MaintenanceEntry) *Ent return _u.RemoveMaintenanceEntryIDs(ids...) } +// ClearMaintenancePlans clears all "maintenance_plans" edges to the MaintenancePlan entity. +func (_u *EntityUpdateOne) ClearMaintenancePlans() *EntityUpdateOne { + _u.mutation.ClearMaintenancePlans() + return _u +} + +// RemoveMaintenancePlanIDs removes the "maintenance_plans" edge to MaintenancePlan entities by IDs. +func (_u *EntityUpdateOne) RemoveMaintenancePlanIDs(ids ...uuid.UUID) *EntityUpdateOne { + _u.mutation.RemoveMaintenancePlanIDs(ids...) + return _u +} + +// RemoveMaintenancePlans removes "maintenance_plans" edges to MaintenancePlan entities. +func (_u *EntityUpdateOne) RemoveMaintenancePlans(v ...*MaintenancePlan) *EntityUpdateOne { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMaintenancePlanIDs(ids...) +} + // ClearAttachments clears all "attachments" edges to the Attachment entity. func (_u *EntityUpdateOne) ClearAttachments() *EntityUpdateOne { _u.mutation.ClearAttachments() @@ -2440,6 +2558,51 @@ func (_u *EntityUpdateOne) sqlSave(ctx context.Context) (_node *Entity, err erro } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.MaintenancePlansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMaintenancePlansIDs(); len(nodes) > 0 && !_u.mutation.MaintenancePlansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MaintenancePlansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: entity.MaintenancePlansTable, + Columns: []string{entity.MaintenancePlansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if _u.mutation.AttachmentsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/backend/internal/data/ent/has_id.go b/backend/internal/data/ent/has_id.go index 7ea3c4a8d..762173d6e 100644 --- a/backend/internal/data/ent/has_id.go +++ b/backend/internal/data/ent/has_id.go @@ -52,6 +52,10 @@ func (_m *MaintenanceEntry) GetID() uuid.UUID { return _m.ID } +func (_m *MaintenancePlan) GetID() uuid.UUID { + return _m.ID +} + func (_m *Notifier) GetID() uuid.UUID { return _m.ID } diff --git a/backend/internal/data/ent/hook/hook.go b/backend/internal/data/ent/hook/hook.go index 504a3df1c..b775c35a5 100644 --- a/backend/internal/data/ent/hook/hook.go +++ b/backend/internal/data/ent/hook/hook.go @@ -153,6 +153,18 @@ func (f MaintenanceEntryFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.V return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MaintenanceEntryMutation", m) } +// The MaintenancePlanFunc type is an adapter to allow the use of ordinary +// function as MaintenancePlan mutator. +type MaintenancePlanFunc func(context.Context, *ent.MaintenancePlanMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f MaintenancePlanFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.MaintenancePlanMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MaintenancePlanMutation", m) +} + // The NotifierFunc type is an adapter to allow the use of ordinary // function as Notifier mutator. type NotifierFunc func(context.Context, *ent.NotifierMutation) (ent.Value, error) diff --git a/backend/internal/data/ent/maintenanceentry.go b/backend/internal/data/ent/maintenanceentry.go index 700de4009..f2bf65750 100644 --- a/backend/internal/data/ent/maintenanceentry.go +++ b/backend/internal/data/ent/maintenanceentry.go @@ -12,6 +12,7 @@ import ( "github.com/google/uuid" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" ) // MaintenanceEntry is the model entity for the MaintenanceEntry schema. @@ -25,6 +26,8 @@ type MaintenanceEntry struct { UpdatedAt time.Time `json:"updated_at,omitempty"` // EntityID holds the value of the "entity_id" field. EntityID uuid.UUID `json:"entity_id,omitempty"` + // PlanID holds the value of the "plan_id" field. + PlanID *uuid.UUID `json:"plan_id,omitempty"` // Date holds the value of the "date" field. Date time.Time `json:"date,omitempty"` // ScheduledDate holds the value of the "scheduled_date" field. @@ -45,9 +48,11 @@ type MaintenanceEntry struct { type MaintenanceEntryEdges struct { // Entity holds the value of the entity edge. Entity *Entity `json:"entity,omitempty"` + // Plan holds the value of the plan edge. + Plan *MaintenancePlan `json:"plan,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [1]bool + loadedTypes [2]bool } // EntityOrErr returns the Entity value or an error if the edge @@ -61,11 +66,24 @@ func (e MaintenanceEntryEdges) EntityOrErr() (*Entity, error) { return nil, &NotLoadedError{edge: "entity"} } +// PlanOrErr returns the Plan value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e MaintenanceEntryEdges) PlanOrErr() (*MaintenancePlan, error) { + if e.Plan != nil { + return e.Plan, nil + } else if e.loadedTypes[1] { + return nil, &NotFoundError{label: maintenanceplan.Label} + } + return nil, &NotLoadedError{edge: "plan"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*MaintenanceEntry) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { + case maintenanceentry.FieldPlanID: + values[i] = &sql.NullScanner{S: new(uuid.UUID)} case maintenanceentry.FieldCost: values[i] = new(sql.NullFloat64) case maintenanceentry.FieldName, maintenanceentry.FieldDescription: @@ -113,6 +131,13 @@ func (_m *MaintenanceEntry) assignValues(columns []string, values []any) error { } else if value != nil { _m.EntityID = *value } + case maintenanceentry.FieldPlanID: + if value, ok := values[i].(*sql.NullScanner); !ok { + return fmt.Errorf("unexpected type %T for field plan_id", values[i]) + } else if value.Valid { + _m.PlanID = new(uuid.UUID) + *_m.PlanID = *value.S.(*uuid.UUID) + } case maintenanceentry.FieldDate: if value, ok := values[i].(*sql.NullTime); !ok { return fmt.Errorf("unexpected type %T for field date", values[i]) @@ -161,6 +186,11 @@ func (_m *MaintenanceEntry) QueryEntity() *EntityQuery { return NewMaintenanceEntryClient(_m.config).QueryEntity(_m) } +// QueryPlan queries the "plan" edge of the MaintenanceEntry entity. +func (_m *MaintenanceEntry) QueryPlan() *MaintenancePlanQuery { + return NewMaintenanceEntryClient(_m.config).QueryPlan(_m) +} + // Update returns a builder for updating this MaintenanceEntry. // Note that you need to call MaintenanceEntry.Unwrap() before calling this method if this MaintenanceEntry // was returned from a transaction, and the transaction was committed or rolled back. @@ -193,6 +223,11 @@ func (_m *MaintenanceEntry) String() string { builder.WriteString("entity_id=") builder.WriteString(fmt.Sprintf("%v", _m.EntityID)) builder.WriteString(", ") + if v := _m.PlanID; v != nil { + builder.WriteString("plan_id=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") builder.WriteString("date=") builder.WriteString(_m.Date.Format(time.ANSIC)) builder.WriteString(", ") diff --git a/backend/internal/data/ent/maintenanceentry/maintenanceentry.go b/backend/internal/data/ent/maintenanceentry/maintenanceentry.go index adf71a516..92ed6580c 100644 --- a/backend/internal/data/ent/maintenanceentry/maintenanceentry.go +++ b/backend/internal/data/ent/maintenanceentry/maintenanceentry.go @@ -21,6 +21,8 @@ const ( FieldUpdatedAt = "updated_at" // FieldEntityID holds the string denoting the entity_id field in the database. FieldEntityID = "entity_id" + // FieldPlanID holds the string denoting the plan_id field in the database. + FieldPlanID = "plan_id" // FieldDate holds the string denoting the date field in the database. FieldDate = "date" // FieldScheduledDate holds the string denoting the scheduled_date field in the database. @@ -33,6 +35,8 @@ const ( FieldCost = "cost" // EdgeEntity holds the string denoting the entity edge name in mutations. EdgeEntity = "entity" + // EdgePlan holds the string denoting the plan edge name in mutations. + EdgePlan = "plan" // Table holds the table name of the maintenanceentry in the database. Table = "maintenance_entries" // EntityTable is the table that holds the entity relation/edge. @@ -42,6 +46,13 @@ const ( EntityInverseTable = "entities" // EntityColumn is the table column denoting the entity relation/edge. EntityColumn = "entity_id" + // PlanTable is the table that holds the plan relation/edge. + PlanTable = "maintenance_entries" + // PlanInverseTable is the table name for the MaintenancePlan entity. + // It exists in this package in order to avoid circular dependency with the "maintenanceplan" package. + PlanInverseTable = "maintenance_plans" + // PlanColumn is the table column denoting the plan relation/edge. + PlanColumn = "plan_id" ) // Columns holds all SQL columns for maintenanceentry fields. @@ -50,6 +61,7 @@ var Columns = []string{ FieldCreatedAt, FieldUpdatedAt, FieldEntityID, + FieldPlanID, FieldDate, FieldScheduledDate, FieldName, @@ -107,6 +119,11 @@ func ByEntityID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldEntityID, opts...).ToFunc() } +// ByPlanID orders the results by the plan_id field. +func ByPlanID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPlanID, opts...).ToFunc() +} + // ByDate orders the results by the date field. func ByDate(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldDate, opts...).ToFunc() @@ -138,6 +155,13 @@ func ByEntityField(field string, opts ...sql.OrderTermOption) OrderOption { sqlgraph.OrderByNeighborTerms(s, newEntityStep(), sql.OrderByField(field, opts...)) } } + +// ByPlanField orders the results by plan field. +func ByPlanField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newPlanStep(), sql.OrderByField(field, opts...)) + } +} func newEntityStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -145,3 +169,10 @@ func newEntityStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.M2O, true, EntityTable, EntityColumn), ) } +func newPlanStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(PlanInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, PlanTable, PlanColumn), + ) +} diff --git a/backend/internal/data/ent/maintenanceentry/where.go b/backend/internal/data/ent/maintenanceentry/where.go index 4e234c0e0..c9fb7cab3 100644 --- a/backend/internal/data/ent/maintenanceentry/where.go +++ b/backend/internal/data/ent/maintenanceentry/where.go @@ -71,6 +71,11 @@ func EntityID(v uuid.UUID) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(sql.FieldEQ(FieldEntityID, v)) } +// PlanID applies equality check predicate on the "plan_id" field. It's identical to PlanIDEQ. +func PlanID(v uuid.UUID) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldEQ(FieldPlanID, v)) +} + // Date applies equality check predicate on the "date" field. It's identical to DateEQ. func Date(v time.Time) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(sql.FieldEQ(FieldDate, v)) @@ -196,6 +201,36 @@ func EntityIDNotIn(vs ...uuid.UUID) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(sql.FieldNotIn(FieldEntityID, vs...)) } +// PlanIDEQ applies the EQ predicate on the "plan_id" field. +func PlanIDEQ(v uuid.UUID) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldEQ(FieldPlanID, v)) +} + +// PlanIDNEQ applies the NEQ predicate on the "plan_id" field. +func PlanIDNEQ(v uuid.UUID) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldNEQ(FieldPlanID, v)) +} + +// PlanIDIn applies the In predicate on the "plan_id" field. +func PlanIDIn(vs ...uuid.UUID) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldIn(FieldPlanID, vs...)) +} + +// PlanIDNotIn applies the NotIn predicate on the "plan_id" field. +func PlanIDNotIn(vs ...uuid.UUID) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldNotIn(FieldPlanID, vs...)) +} + +// PlanIDIsNil applies the IsNil predicate on the "plan_id" field. +func PlanIDIsNil() predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldIsNull(FieldPlanID)) +} + +// PlanIDNotNil applies the NotNil predicate on the "plan_id" field. +func PlanIDNotNil() predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(sql.FieldNotNull(FieldPlanID)) +} + // DateEQ applies the EQ predicate on the "date" field. func DateEQ(v time.Time) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(sql.FieldEQ(FieldDate, v)) @@ -499,6 +534,29 @@ func HasEntityWith(preds ...predicate.Entity) predicate.MaintenanceEntry { }) } +// HasPlan applies the HasEdge predicate on the "plan" edge. +func HasPlan() predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, PlanTable, PlanColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasPlanWith applies the HasEdge predicate on the "plan" edge with a given conditions (other predicates). +func HasPlanWith(preds ...predicate.MaintenancePlan) predicate.MaintenanceEntry { + return predicate.MaintenanceEntry(func(s *sql.Selector) { + step := newPlanStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(sql.AndPredicates(predicates...)) diff --git a/backend/internal/data/ent/maintenanceentry_create.go b/backend/internal/data/ent/maintenanceentry_create.go index 8cb472eb0..f13b9e69c 100644 --- a/backend/internal/data/ent/maintenanceentry_create.go +++ b/backend/internal/data/ent/maintenanceentry_create.go @@ -13,6 +13,7 @@ import ( "github.com/google/uuid" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" ) // MaintenanceEntryCreate is the builder for creating a MaintenanceEntry entity. @@ -56,6 +57,20 @@ func (_c *MaintenanceEntryCreate) SetEntityID(v uuid.UUID) *MaintenanceEntryCrea return _c } +// SetPlanID sets the "plan_id" field. +func (_c *MaintenanceEntryCreate) SetPlanID(v uuid.UUID) *MaintenanceEntryCreate { + _c.mutation.SetPlanID(v) + return _c +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_c *MaintenanceEntryCreate) SetNillablePlanID(v *uuid.UUID) *MaintenanceEntryCreate { + if v != nil { + _c.SetPlanID(*v) + } + return _c +} + // SetDate sets the "date" field. func (_c *MaintenanceEntryCreate) SetDate(v time.Time) *MaintenanceEntryCreate { _c.mutation.SetDate(v) @@ -137,6 +152,11 @@ func (_c *MaintenanceEntryCreate) SetEntity(v *Entity) *MaintenanceEntryCreate { return _c.SetEntityID(v.ID) } +// SetPlan sets the "plan" edge to the MaintenancePlan entity. +func (_c *MaintenanceEntryCreate) SetPlan(v *MaintenancePlan) *MaintenanceEntryCreate { + return _c.SetPlanID(v.ID) +} + // Mutation returns the MaintenanceEntryMutation object of the builder. func (_c *MaintenanceEntryCreate) Mutation() *MaintenanceEntryMutation { return _c.mutation @@ -300,6 +320,23 @@ func (_c *MaintenanceEntryCreate) createSpec() (*MaintenanceEntry, *sqlgraph.Cre _node.EntityID = nodes[0] _spec.Edges = append(_spec.Edges, edge) } + if nodes := _c.mutation.PlanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceentry.PlanTable, + Columns: []string{maintenanceentry.PlanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.PlanID = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } diff --git a/backend/internal/data/ent/maintenanceentry_query.go b/backend/internal/data/ent/maintenanceentry_query.go index 6b9eaabb1..6c02b3cfa 100644 --- a/backend/internal/data/ent/maintenanceentry_query.go +++ b/backend/internal/data/ent/maintenanceentry_query.go @@ -14,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" ) @@ -25,6 +26,7 @@ type MaintenanceEntryQuery struct { inters []Interceptor predicates []predicate.MaintenanceEntry withEntity *EntityQuery + withPlan *MaintenancePlanQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -83,6 +85,28 @@ func (_q *MaintenanceEntryQuery) QueryEntity() *EntityQuery { return query } +// QueryPlan chains the current query on the "plan" edge. +func (_q *MaintenanceEntryQuery) QueryPlan() *MaintenancePlanQuery { + query := (&MaintenancePlanClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceentry.Table, maintenanceentry.FieldID, selector), + sqlgraph.To(maintenanceplan.Table, maintenanceplan.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, maintenanceentry.PlanTable, maintenanceentry.PlanColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first MaintenanceEntry entity from the query. // Returns a *NotFoundError when no MaintenanceEntry was found. func (_q *MaintenanceEntryQuery) First(ctx context.Context) (*MaintenanceEntry, error) { @@ -276,6 +300,7 @@ func (_q *MaintenanceEntryQuery) Clone() *MaintenanceEntryQuery { inters: append([]Interceptor{}, _q.inters...), predicates: append([]predicate.MaintenanceEntry{}, _q.predicates...), withEntity: _q.withEntity.Clone(), + withPlan: _q.withPlan.Clone(), // clone intermediate query. sql: _q.sql.Clone(), path: _q.path, @@ -293,6 +318,17 @@ func (_q *MaintenanceEntryQuery) WithEntity(opts ...func(*EntityQuery)) *Mainten return _q } +// WithPlan tells the query-builder to eager-load the nodes that are connected to +// the "plan" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *MaintenanceEntryQuery) WithPlan(opts ...func(*MaintenancePlanQuery)) *MaintenanceEntryQuery { + query := (&MaintenancePlanClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withPlan = query + return _q +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -371,8 +407,9 @@ func (_q *MaintenanceEntryQuery) sqlAll(ctx context.Context, hooks ...queryHook) var ( nodes = []*MaintenanceEntry{} _spec = _q.querySpec() - loadedTypes = [1]bool{ + loadedTypes = [2]bool{ _q.withEntity != nil, + _q.withPlan != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -399,6 +436,12 @@ func (_q *MaintenanceEntryQuery) sqlAll(ctx context.Context, hooks ...queryHook) return nil, err } } + if query := _q.withPlan; query != nil { + if err := _q.loadPlan(ctx, query, nodes, nil, + func(n *MaintenanceEntry, e *MaintenancePlan) { n.Edges.Plan = e }); err != nil { + return nil, err + } + } return nodes, nil } @@ -431,6 +474,38 @@ func (_q *MaintenanceEntryQuery) loadEntity(ctx context.Context, query *EntityQu } return nil } +func (_q *MaintenanceEntryQuery) loadPlan(ctx context.Context, query *MaintenancePlanQuery, nodes []*MaintenanceEntry, init func(*MaintenanceEntry), assign func(*MaintenanceEntry, *MaintenancePlan)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*MaintenanceEntry) + for i := range nodes { + if nodes[i].PlanID == nil { + continue + } + fk := *nodes[i].PlanID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(maintenanceplan.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "plan_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} func (_q *MaintenanceEntryQuery) sqlCount(ctx context.Context) (int, error) { _spec := _q.querySpec() @@ -460,6 +535,9 @@ func (_q *MaintenanceEntryQuery) querySpec() *sqlgraph.QuerySpec { if _q.withEntity != nil { _spec.Node.AddColumnOnce(maintenanceentry.FieldEntityID) } + if _q.withPlan != nil { + _spec.Node.AddColumnOnce(maintenanceentry.FieldPlanID) + } } if ps := _q.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/backend/internal/data/ent/maintenanceentry_update.go b/backend/internal/data/ent/maintenanceentry_update.go index c57d688be..991d9ff4e 100644 --- a/backend/internal/data/ent/maintenanceentry_update.go +++ b/backend/internal/data/ent/maintenanceentry_update.go @@ -14,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" ) @@ -50,6 +51,26 @@ func (_u *MaintenanceEntryUpdate) SetNillableEntityID(v *uuid.UUID) *Maintenance return _u } +// SetPlanID sets the "plan_id" field. +func (_u *MaintenanceEntryUpdate) SetPlanID(v uuid.UUID) *MaintenanceEntryUpdate { + _u.mutation.SetPlanID(v) + return _u +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_u *MaintenanceEntryUpdate) SetNillablePlanID(v *uuid.UUID) *MaintenanceEntryUpdate { + if v != nil { + _u.SetPlanID(*v) + } + return _u +} + +// ClearPlanID clears the value of the "plan_id" field. +func (_u *MaintenanceEntryUpdate) ClearPlanID() *MaintenanceEntryUpdate { + _u.mutation.ClearPlanID() + return _u +} + // SetDate sets the "date" field. func (_u *MaintenanceEntryUpdate) SetDate(v time.Time) *MaintenanceEntryUpdate { _u.mutation.SetDate(v) @@ -150,6 +171,11 @@ func (_u *MaintenanceEntryUpdate) SetEntity(v *Entity) *MaintenanceEntryUpdate { return _u.SetEntityID(v.ID) } +// SetPlan sets the "plan" edge to the MaintenancePlan entity. +func (_u *MaintenanceEntryUpdate) SetPlan(v *MaintenancePlan) *MaintenanceEntryUpdate { + return _u.SetPlanID(v.ID) +} + // Mutation returns the MaintenanceEntryMutation object of the builder. func (_u *MaintenanceEntryUpdate) Mutation() *MaintenanceEntryMutation { return _u.mutation @@ -161,6 +187,12 @@ func (_u *MaintenanceEntryUpdate) ClearEntity() *MaintenanceEntryUpdate { return _u } +// ClearPlan clears the "plan" edge to the MaintenancePlan entity. +func (_u *MaintenanceEntryUpdate) ClearPlan() *MaintenanceEntryUpdate { + _u.mutation.ClearPlan() + return _u +} + // Save executes the query and returns the number of nodes affected by the update operation. func (_u *MaintenanceEntryUpdate) Save(ctx context.Context) (int, error) { _u.defaults() @@ -286,6 +318,35 @@ func (_u *MaintenanceEntryUpdate) sqlSave(ctx context.Context) (_node int, err e } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.PlanCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceentry.PlanTable, + Columns: []string{maintenanceentry.PlanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.PlanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceentry.PlanTable, + Columns: []string{maintenanceentry.PlanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{maintenanceentry.Label} @@ -326,6 +387,26 @@ func (_u *MaintenanceEntryUpdateOne) SetNillableEntityID(v *uuid.UUID) *Maintena return _u } +// SetPlanID sets the "plan_id" field. +func (_u *MaintenanceEntryUpdateOne) SetPlanID(v uuid.UUID) *MaintenanceEntryUpdateOne { + _u.mutation.SetPlanID(v) + return _u +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_u *MaintenanceEntryUpdateOne) SetNillablePlanID(v *uuid.UUID) *MaintenanceEntryUpdateOne { + if v != nil { + _u.SetPlanID(*v) + } + return _u +} + +// ClearPlanID clears the value of the "plan_id" field. +func (_u *MaintenanceEntryUpdateOne) ClearPlanID() *MaintenanceEntryUpdateOne { + _u.mutation.ClearPlanID() + return _u +} + // SetDate sets the "date" field. func (_u *MaintenanceEntryUpdateOne) SetDate(v time.Time) *MaintenanceEntryUpdateOne { _u.mutation.SetDate(v) @@ -426,6 +507,11 @@ func (_u *MaintenanceEntryUpdateOne) SetEntity(v *Entity) *MaintenanceEntryUpdat return _u.SetEntityID(v.ID) } +// SetPlan sets the "plan" edge to the MaintenancePlan entity. +func (_u *MaintenanceEntryUpdateOne) SetPlan(v *MaintenancePlan) *MaintenanceEntryUpdateOne { + return _u.SetPlanID(v.ID) +} + // Mutation returns the MaintenanceEntryMutation object of the builder. func (_u *MaintenanceEntryUpdateOne) Mutation() *MaintenanceEntryMutation { return _u.mutation @@ -437,6 +523,12 @@ func (_u *MaintenanceEntryUpdateOne) ClearEntity() *MaintenanceEntryUpdateOne { return _u } +// ClearPlan clears the "plan" edge to the MaintenancePlan entity. +func (_u *MaintenanceEntryUpdateOne) ClearPlan() *MaintenanceEntryUpdateOne { + _u.mutation.ClearPlan() + return _u +} + // Where appends a list predicates to the MaintenanceEntryUpdate builder. func (_u *MaintenanceEntryUpdateOne) Where(ps ...predicate.MaintenanceEntry) *MaintenanceEntryUpdateOne { _u.mutation.Where(ps...) @@ -592,6 +684,35 @@ func (_u *MaintenanceEntryUpdateOne) sqlSave(ctx context.Context) (_node *Mainte } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.PlanCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceentry.PlanTable, + Columns: []string{maintenanceentry.PlanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.PlanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceentry.PlanTable, + Columns: []string{maintenanceentry.PlanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &MaintenanceEntry{config: _u.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/backend/internal/data/ent/maintenanceplan.go b/backend/internal/data/ent/maintenanceplan.go new file mode 100644 index 000000000..49bc2b091 --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan.go @@ -0,0 +1,261 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" +) + +// MaintenancePlan is the model entity for the MaintenancePlan schema. +type MaintenancePlan struct { + config `json:"-"` + // ID of the ent. + ID uuid.UUID `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UpdatedAt holds the value of the "updated_at" field. + UpdatedAt time.Time `json:"updated_at,omitempty"` + // EntityID holds the value of the "entity_id" field. + EntityID uuid.UUID `json:"entity_id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` + // IntervalValue holds the value of the "interval_value" field. + IntervalValue int `json:"interval_value,omitempty"` + // IntervalUnit holds the value of the "interval_unit" field. + IntervalUnit maintenanceplan.IntervalUnit `json:"interval_unit,omitempty"` + // Active holds the value of the "active" field. + Active bool `json:"active,omitempty"` + // LastCompletedAt holds the value of the "last_completed_at" field. + LastCompletedAt *time.Time `json:"last_completed_at,omitempty"` + // NextDueAt holds the value of the "next_due_at" field. + NextDueAt *time.Time `json:"next_due_at,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the MaintenancePlanQuery when eager-loading is set. + Edges MaintenancePlanEdges `json:"edges"` + selectValues sql.SelectValues +} + +// MaintenancePlanEdges holds the relations/edges for other nodes in the graph. +type MaintenancePlanEdges struct { + // Entity holds the value of the entity edge. + Entity *Entity `json:"entity,omitempty"` + // MaintenanceEntries holds the value of the maintenance_entries edge. + MaintenanceEntries []*MaintenanceEntry `json:"maintenance_entries,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [2]bool +} + +// EntityOrErr returns the Entity value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e MaintenancePlanEdges) EntityOrErr() (*Entity, error) { + if e.Entity != nil { + return e.Entity, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: entity.Label} + } + return nil, &NotLoadedError{edge: "entity"} +} + +// MaintenanceEntriesOrErr returns the MaintenanceEntries value or an error if the edge +// was not loaded in eager-loading. +func (e MaintenancePlanEdges) MaintenanceEntriesOrErr() ([]*MaintenanceEntry, error) { + if e.loadedTypes[1] { + return e.MaintenanceEntries, nil + } + return nil, &NotLoadedError{edge: "maintenance_entries"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*MaintenancePlan) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case maintenanceplan.FieldActive: + values[i] = new(sql.NullBool) + case maintenanceplan.FieldIntervalValue: + values[i] = new(sql.NullInt64) + case maintenanceplan.FieldName, maintenanceplan.FieldDescription, maintenanceplan.FieldIntervalUnit: + values[i] = new(sql.NullString) + case maintenanceplan.FieldCreatedAt, maintenanceplan.FieldUpdatedAt, maintenanceplan.FieldLastCompletedAt, maintenanceplan.FieldNextDueAt: + values[i] = new(sql.NullTime) + case maintenanceplan.FieldID, maintenanceplan.FieldEntityID: + values[i] = new(uuid.UUID) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the MaintenancePlan fields. +func (_m *MaintenancePlan) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case maintenanceplan.FieldID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value != nil { + _m.ID = *value + } + case maintenanceplan.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + _m.CreatedAt = value.Time + } + case maintenanceplan.FieldUpdatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field updated_at", values[i]) + } else if value.Valid { + _m.UpdatedAt = value.Time + } + case maintenanceplan.FieldEntityID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field entity_id", values[i]) + } else if value != nil { + _m.EntityID = *value + } + case maintenanceplan.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + _m.Name = value.String + } + case maintenanceplan.FieldDescription: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field description", values[i]) + } else if value.Valid { + _m.Description = value.String + } + case maintenanceplan.FieldIntervalValue: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field interval_value", values[i]) + } else if value.Valid { + _m.IntervalValue = int(value.Int64) + } + case maintenanceplan.FieldIntervalUnit: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field interval_unit", values[i]) + } else if value.Valid { + _m.IntervalUnit = maintenanceplan.IntervalUnit(value.String) + } + case maintenanceplan.FieldActive: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field active", values[i]) + } else if value.Valid { + _m.Active = value.Bool + } + case maintenanceplan.FieldLastCompletedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field last_completed_at", values[i]) + } else if value.Valid { + _m.LastCompletedAt = new(time.Time) + *_m.LastCompletedAt = value.Time + } + case maintenanceplan.FieldNextDueAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field next_due_at", values[i]) + } else if value.Valid { + _m.NextDueAt = new(time.Time) + *_m.NextDueAt = value.Time + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the MaintenancePlan. +// This includes values selected through modifiers, order, etc. +func (_m *MaintenancePlan) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryEntity queries the "entity" edge of the MaintenancePlan entity. +func (_m *MaintenancePlan) QueryEntity() *EntityQuery { + return NewMaintenancePlanClient(_m.config).QueryEntity(_m) +} + +// QueryMaintenanceEntries queries the "maintenance_entries" edge of the MaintenancePlan entity. +func (_m *MaintenancePlan) QueryMaintenanceEntries() *MaintenanceEntryQuery { + return NewMaintenancePlanClient(_m.config).QueryMaintenanceEntries(_m) +} + +// Update returns a builder for updating this MaintenancePlan. +// Note that you need to call MaintenancePlan.Unwrap() before calling this method if this MaintenancePlan +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *MaintenancePlan) Update() *MaintenancePlanUpdateOne { + return NewMaintenancePlanClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the MaintenancePlan entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *MaintenancePlan) Unwrap() *MaintenancePlan { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: MaintenancePlan is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *MaintenancePlan) String() string { + var builder strings.Builder + builder.WriteString("MaintenancePlan(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("created_at=") + builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(_m.UpdatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("entity_id=") + builder.WriteString(fmt.Sprintf("%v", _m.EntityID)) + builder.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(_m.Name) + builder.WriteString(", ") + builder.WriteString("description=") + builder.WriteString(_m.Description) + builder.WriteString(", ") + builder.WriteString("interval_value=") + builder.WriteString(fmt.Sprintf("%v", _m.IntervalValue)) + builder.WriteString(", ") + builder.WriteString("interval_unit=") + builder.WriteString(fmt.Sprintf("%v", _m.IntervalUnit)) + builder.WriteString(", ") + builder.WriteString("active=") + builder.WriteString(fmt.Sprintf("%v", _m.Active)) + builder.WriteString(", ") + if v := _m.LastCompletedAt; v != nil { + builder.WriteString("last_completed_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + if v := _m.NextDueAt; v != nil { + builder.WriteString("next_due_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteByte(')') + return builder.String() +} + +// MaintenancePlans is a parsable slice of MaintenancePlan. +type MaintenancePlans []*MaintenancePlan diff --git a/backend/internal/data/ent/maintenanceplan/maintenanceplan.go b/backend/internal/data/ent/maintenanceplan/maintenanceplan.go new file mode 100644 index 000000000..387c71b13 --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan/maintenanceplan.go @@ -0,0 +1,222 @@ +// Code generated by ent, DO NOT EDIT. + +package maintenanceplan + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/google/uuid" +) + +const ( + // Label holds the string label denoting the maintenanceplan type in the database. + Label = "maintenance_plan" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUpdatedAt holds the string denoting the updated_at field in the database. + FieldUpdatedAt = "updated_at" + // FieldEntityID holds the string denoting the entity_id field in the database. + FieldEntityID = "entity_id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" + // FieldIntervalValue holds the string denoting the interval_value field in the database. + FieldIntervalValue = "interval_value" + // FieldIntervalUnit holds the string denoting the interval_unit field in the database. + FieldIntervalUnit = "interval_unit" + // FieldActive holds the string denoting the active field in the database. + FieldActive = "active" + // FieldLastCompletedAt holds the string denoting the last_completed_at field in the database. + FieldLastCompletedAt = "last_completed_at" + // FieldNextDueAt holds the string denoting the next_due_at field in the database. + FieldNextDueAt = "next_due_at" + // EdgeEntity holds the string denoting the entity edge name in mutations. + EdgeEntity = "entity" + // EdgeMaintenanceEntries holds the string denoting the maintenance_entries edge name in mutations. + EdgeMaintenanceEntries = "maintenance_entries" + // Table holds the table name of the maintenanceplan in the database. + Table = "maintenance_plans" + // EntityTable is the table that holds the entity relation/edge. + EntityTable = "maintenance_plans" + // EntityInverseTable is the table name for the Entity entity. + // It exists in this package in order to avoid circular dependency with the "entity" package. + EntityInverseTable = "entities" + // EntityColumn is the table column denoting the entity relation/edge. + EntityColumn = "entity_id" + // MaintenanceEntriesTable is the table that holds the maintenance_entries relation/edge. + MaintenanceEntriesTable = "maintenance_entries" + // MaintenanceEntriesInverseTable is the table name for the MaintenanceEntry entity. + // It exists in this package in order to avoid circular dependency with the "maintenanceentry" package. + MaintenanceEntriesInverseTable = "maintenance_entries" + // MaintenanceEntriesColumn is the table column denoting the maintenance_entries relation/edge. + MaintenanceEntriesColumn = "plan_id" +) + +// Columns holds all SQL columns for maintenanceplan fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldEntityID, + FieldName, + FieldDescription, + FieldIntervalValue, + FieldIntervalUnit, + FieldActive, + FieldLastCompletedAt, + FieldNextDueAt, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultUpdatedAt holds the default value on creation for the "updated_at" field. + DefaultUpdatedAt func() time.Time + // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. + UpdateDefaultUpdatedAt func() time.Time + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + DescriptionValidator func(string) error + // IntervalValueValidator is a validator for the "interval_value" field. It is called by the builders before save. + IntervalValueValidator func(int) error + // DefaultActive holds the default value on creation for the "active" field. + DefaultActive bool + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() uuid.UUID +) + +// IntervalUnit defines the type for the "interval_unit" enum field. +type IntervalUnit string + +// IntervalUnit values. +const ( + IntervalUnitHour IntervalUnit = "hour" + IntervalUnitDay IntervalUnit = "day" + IntervalUnitWeek IntervalUnit = "week" + IntervalUnitMonth IntervalUnit = "month" + IntervalUnitYear IntervalUnit = "year" +) + +func (iu IntervalUnit) String() string { + return string(iu) +} + +// IntervalUnitValidator is a validator for the "interval_unit" field enum values. It is called by the builders before save. +func IntervalUnitValidator(iu IntervalUnit) error { + switch iu { + case IntervalUnitHour, IntervalUnitDay, IntervalUnitWeek, IntervalUnitMonth, IntervalUnitYear: + return nil + default: + return fmt.Errorf("maintenanceplan: invalid enum value for interval_unit field: %q", iu) + } +} + +// OrderOption defines the ordering options for the MaintenancePlan queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUpdatedAt orders the results by the updated_at field. +func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() +} + +// ByEntityID orders the results by the entity_id field. +func ByEntityID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEntityID, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByDescription orders the results by the description field. +func ByDescription(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDescription, opts...).ToFunc() +} + +// ByIntervalValue orders the results by the interval_value field. +func ByIntervalValue(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldIntervalValue, opts...).ToFunc() +} + +// ByIntervalUnit orders the results by the interval_unit field. +func ByIntervalUnit(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldIntervalUnit, opts...).ToFunc() +} + +// ByActive orders the results by the active field. +func ByActive(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldActive, opts...).ToFunc() +} + +// ByLastCompletedAt orders the results by the last_completed_at field. +func ByLastCompletedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLastCompletedAt, opts...).ToFunc() +} + +// ByNextDueAt orders the results by the next_due_at field. +func ByNextDueAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldNextDueAt, opts...).ToFunc() +} + +// ByEntityField orders the results by entity field. +func ByEntityField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newEntityStep(), sql.OrderByField(field, opts...)) + } +} + +// ByMaintenanceEntriesCount orders the results by maintenance_entries count. +func ByMaintenanceEntriesCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMaintenanceEntriesStep(), opts...) + } +} + +// ByMaintenanceEntries orders the results by maintenance_entries terms. +func ByMaintenanceEntries(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMaintenanceEntriesStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newEntityStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(EntityInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, EntityTable, EntityColumn), + ) +} +func newMaintenanceEntriesStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MaintenanceEntriesInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, MaintenanceEntriesTable, MaintenanceEntriesColumn), + ) +} diff --git a/backend/internal/data/ent/maintenanceplan/where.go b/backend/internal/data/ent/maintenanceplan/where.go new file mode 100644 index 000000000..d797ed3ed --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan/where.go @@ -0,0 +1,573 @@ +// Code generated by ent, DO NOT EDIT. + +package maintenanceplan + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldCreatedAt, v)) +} + +// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ. +func UpdatedAt(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// EntityID applies equality check predicate on the "entity_id" field. It's identical to EntityIDEQ. +func EntityID(v uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldEntityID, v)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldName, v)) +} + +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldDescription, v)) +} + +// IntervalValue applies equality check predicate on the "interval_value" field. It's identical to IntervalValueEQ. +func IntervalValue(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldIntervalValue, v)) +} + +// Active applies equality check predicate on the "active" field. It's identical to ActiveEQ. +func Active(v bool) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldActive, v)) +} + +// LastCompletedAt applies equality check predicate on the "last_completed_at" field. It's identical to LastCompletedAtEQ. +func LastCompletedAt(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldLastCompletedAt, v)) +} + +// NextDueAt applies equality check predicate on the "next_due_at" field. It's identical to NextDueAtEQ. +func NextDueAt(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldNextDueAt, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// EntityIDEQ applies the EQ predicate on the "entity_id" field. +func EntityIDEQ(v uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldEntityID, v)) +} + +// EntityIDNEQ applies the NEQ predicate on the "entity_id" field. +func EntityIDNEQ(v uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldEntityID, v)) +} + +// EntityIDIn applies the In predicate on the "entity_id" field. +func EntityIDIn(vs ...uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldEntityID, vs...)) +} + +// EntityIDNotIn applies the NotIn predicate on the "entity_id" field. +func EntityIDNotIn(vs ...uuid.UUID) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldEntityID, vs...)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldContainsFold(FieldName, v)) +} + +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldDescription, v)) +} + +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldDescription, v)) +} + +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldDescription, vs...)) +} + +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldDescription, vs...)) +} + +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldDescription, v)) +} + +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldDescription, v)) +} + +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldDescription, v)) +} + +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldDescription, v)) +} + +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldContains(FieldDescription, v)) +} + +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldHasPrefix(FieldDescription, v)) +} + +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldHasSuffix(FieldDescription, v)) +} + +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIsNull(FieldDescription)) +} + +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotNull(FieldDescription)) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEqualFold(FieldDescription, v)) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldContainsFold(FieldDescription, v)) +} + +// IntervalValueEQ applies the EQ predicate on the "interval_value" field. +func IntervalValueEQ(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldIntervalValue, v)) +} + +// IntervalValueNEQ applies the NEQ predicate on the "interval_value" field. +func IntervalValueNEQ(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldIntervalValue, v)) +} + +// IntervalValueIn applies the In predicate on the "interval_value" field. +func IntervalValueIn(vs ...int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldIntervalValue, vs...)) +} + +// IntervalValueNotIn applies the NotIn predicate on the "interval_value" field. +func IntervalValueNotIn(vs ...int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldIntervalValue, vs...)) +} + +// IntervalValueGT applies the GT predicate on the "interval_value" field. +func IntervalValueGT(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldIntervalValue, v)) +} + +// IntervalValueGTE applies the GTE predicate on the "interval_value" field. +func IntervalValueGTE(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldIntervalValue, v)) +} + +// IntervalValueLT applies the LT predicate on the "interval_value" field. +func IntervalValueLT(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldIntervalValue, v)) +} + +// IntervalValueLTE applies the LTE predicate on the "interval_value" field. +func IntervalValueLTE(v int) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldIntervalValue, v)) +} + +// IntervalUnitEQ applies the EQ predicate on the "interval_unit" field. +func IntervalUnitEQ(v IntervalUnit) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldIntervalUnit, v)) +} + +// IntervalUnitNEQ applies the NEQ predicate on the "interval_unit" field. +func IntervalUnitNEQ(v IntervalUnit) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldIntervalUnit, v)) +} + +// IntervalUnitIn applies the In predicate on the "interval_unit" field. +func IntervalUnitIn(vs ...IntervalUnit) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldIntervalUnit, vs...)) +} + +// IntervalUnitNotIn applies the NotIn predicate on the "interval_unit" field. +func IntervalUnitNotIn(vs ...IntervalUnit) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldIntervalUnit, vs...)) +} + +// ActiveEQ applies the EQ predicate on the "active" field. +func ActiveEQ(v bool) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldActive, v)) +} + +// ActiveNEQ applies the NEQ predicate on the "active" field. +func ActiveNEQ(v bool) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldActive, v)) +} + +// LastCompletedAtEQ applies the EQ predicate on the "last_completed_at" field. +func LastCompletedAtEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldLastCompletedAt, v)) +} + +// LastCompletedAtNEQ applies the NEQ predicate on the "last_completed_at" field. +func LastCompletedAtNEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldLastCompletedAt, v)) +} + +// LastCompletedAtIn applies the In predicate on the "last_completed_at" field. +func LastCompletedAtIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldLastCompletedAt, vs...)) +} + +// LastCompletedAtNotIn applies the NotIn predicate on the "last_completed_at" field. +func LastCompletedAtNotIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldLastCompletedAt, vs...)) +} + +// LastCompletedAtGT applies the GT predicate on the "last_completed_at" field. +func LastCompletedAtGT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldLastCompletedAt, v)) +} + +// LastCompletedAtGTE applies the GTE predicate on the "last_completed_at" field. +func LastCompletedAtGTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldLastCompletedAt, v)) +} + +// LastCompletedAtLT applies the LT predicate on the "last_completed_at" field. +func LastCompletedAtLT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldLastCompletedAt, v)) +} + +// LastCompletedAtLTE applies the LTE predicate on the "last_completed_at" field. +func LastCompletedAtLTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldLastCompletedAt, v)) +} + +// LastCompletedAtIsNil applies the IsNil predicate on the "last_completed_at" field. +func LastCompletedAtIsNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIsNull(FieldLastCompletedAt)) +} + +// LastCompletedAtNotNil applies the NotNil predicate on the "last_completed_at" field. +func LastCompletedAtNotNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotNull(FieldLastCompletedAt)) +} + +// NextDueAtEQ applies the EQ predicate on the "next_due_at" field. +func NextDueAtEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldEQ(FieldNextDueAt, v)) +} + +// NextDueAtNEQ applies the NEQ predicate on the "next_due_at" field. +func NextDueAtNEQ(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNEQ(FieldNextDueAt, v)) +} + +// NextDueAtIn applies the In predicate on the "next_due_at" field. +func NextDueAtIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIn(FieldNextDueAt, vs...)) +} + +// NextDueAtNotIn applies the NotIn predicate on the "next_due_at" field. +func NextDueAtNotIn(vs ...time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotIn(FieldNextDueAt, vs...)) +} + +// NextDueAtGT applies the GT predicate on the "next_due_at" field. +func NextDueAtGT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGT(FieldNextDueAt, v)) +} + +// NextDueAtGTE applies the GTE predicate on the "next_due_at" field. +func NextDueAtGTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldGTE(FieldNextDueAt, v)) +} + +// NextDueAtLT applies the LT predicate on the "next_due_at" field. +func NextDueAtLT(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLT(FieldNextDueAt, v)) +} + +// NextDueAtLTE applies the LTE predicate on the "next_due_at" field. +func NextDueAtLTE(v time.Time) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldLTE(FieldNextDueAt, v)) +} + +// NextDueAtIsNil applies the IsNil predicate on the "next_due_at" field. +func NextDueAtIsNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldIsNull(FieldNextDueAt)) +} + +// NextDueAtNotNil applies the NotNil predicate on the "next_due_at" field. +func NextDueAtNotNil() predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.FieldNotNull(FieldNextDueAt)) +} + +// HasEntity applies the HasEdge predicate on the "entity" edge. +func HasEntity() predicate.MaintenancePlan { + return predicate.MaintenancePlan(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, EntityTable, EntityColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasEntityWith applies the HasEdge predicate on the "entity" edge with a given conditions (other predicates). +func HasEntityWith(preds ...predicate.Entity) predicate.MaintenancePlan { + return predicate.MaintenancePlan(func(s *sql.Selector) { + step := newEntityStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasMaintenanceEntries applies the HasEdge predicate on the "maintenance_entries" edge. +func HasMaintenanceEntries() predicate.MaintenancePlan { + return predicate.MaintenancePlan(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, MaintenanceEntriesTable, MaintenanceEntriesColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMaintenanceEntriesWith applies the HasEdge predicate on the "maintenance_entries" edge with a given conditions (other predicates). +func HasMaintenanceEntriesWith(preds ...predicate.MaintenanceEntry) predicate.MaintenancePlan { + return predicate.MaintenancePlan(func(s *sql.Selector) { + step := newMaintenanceEntriesStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.MaintenancePlan) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.MaintenancePlan) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.MaintenancePlan) predicate.MaintenancePlan { + return predicate.MaintenancePlan(sql.NotPredicates(p)) +} diff --git a/backend/internal/data/ent/maintenanceplan_create.go b/backend/internal/data/ent/maintenanceplan_create.go new file mode 100644 index 000000000..dd92ef314 --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan_create.go @@ -0,0 +1,456 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" +) + +// MaintenancePlanCreate is the builder for creating a MaintenancePlan entity. +type MaintenancePlanCreate struct { + config + mutation *MaintenancePlanMutation + hooks []Hook +} + +// SetCreatedAt sets the "created_at" field. +func (_c *MaintenancePlanCreate) SetCreatedAt(v time.Time) *MaintenancePlanCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableCreatedAt(v *time.Time) *MaintenancePlanCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *MaintenancePlanCreate) SetUpdatedAt(v time.Time) *MaintenancePlanCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableUpdatedAt(v *time.Time) *MaintenancePlanCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// SetEntityID sets the "entity_id" field. +func (_c *MaintenancePlanCreate) SetEntityID(v uuid.UUID) *MaintenancePlanCreate { + _c.mutation.SetEntityID(v) + return _c +} + +// SetName sets the "name" field. +func (_c *MaintenancePlanCreate) SetName(v string) *MaintenancePlanCreate { + _c.mutation.SetName(v) + return _c +} + +// SetDescription sets the "description" field. +func (_c *MaintenancePlanCreate) SetDescription(v string) *MaintenancePlanCreate { + _c.mutation.SetDescription(v) + return _c +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableDescription(v *string) *MaintenancePlanCreate { + if v != nil { + _c.SetDescription(*v) + } + return _c +} + +// SetIntervalValue sets the "interval_value" field. +func (_c *MaintenancePlanCreate) SetIntervalValue(v int) *MaintenancePlanCreate { + _c.mutation.SetIntervalValue(v) + return _c +} + +// SetIntervalUnit sets the "interval_unit" field. +func (_c *MaintenancePlanCreate) SetIntervalUnit(v maintenanceplan.IntervalUnit) *MaintenancePlanCreate { + _c.mutation.SetIntervalUnit(v) + return _c +} + +// SetActive sets the "active" field. +func (_c *MaintenancePlanCreate) SetActive(v bool) *MaintenancePlanCreate { + _c.mutation.SetActive(v) + return _c +} + +// SetNillableActive sets the "active" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableActive(v *bool) *MaintenancePlanCreate { + if v != nil { + _c.SetActive(*v) + } + return _c +} + +// SetLastCompletedAt sets the "last_completed_at" field. +func (_c *MaintenancePlanCreate) SetLastCompletedAt(v time.Time) *MaintenancePlanCreate { + _c.mutation.SetLastCompletedAt(v) + return _c +} + +// SetNillableLastCompletedAt sets the "last_completed_at" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableLastCompletedAt(v *time.Time) *MaintenancePlanCreate { + if v != nil { + _c.SetLastCompletedAt(*v) + } + return _c +} + +// SetNextDueAt sets the "next_due_at" field. +func (_c *MaintenancePlanCreate) SetNextDueAt(v time.Time) *MaintenancePlanCreate { + _c.mutation.SetNextDueAt(v) + return _c +} + +// SetNillableNextDueAt sets the "next_due_at" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableNextDueAt(v *time.Time) *MaintenancePlanCreate { + if v != nil { + _c.SetNextDueAt(*v) + } + return _c +} + +// SetID sets the "id" field. +func (_c *MaintenancePlanCreate) SetID(v uuid.UUID) *MaintenancePlanCreate { + _c.mutation.SetID(v) + return _c +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (_c *MaintenancePlanCreate) SetNillableID(v *uuid.UUID) *MaintenancePlanCreate { + if v != nil { + _c.SetID(*v) + } + return _c +} + +// SetEntity sets the "entity" edge to the Entity entity. +func (_c *MaintenancePlanCreate) SetEntity(v *Entity) *MaintenancePlanCreate { + return _c.SetEntityID(v.ID) +} + +// AddMaintenanceEntryIDs adds the "maintenance_entries" edge to the MaintenanceEntry entity by IDs. +func (_c *MaintenancePlanCreate) AddMaintenanceEntryIDs(ids ...uuid.UUID) *MaintenancePlanCreate { + _c.mutation.AddMaintenanceEntryIDs(ids...) + return _c +} + +// AddMaintenanceEntries adds the "maintenance_entries" edges to the MaintenanceEntry entity. +func (_c *MaintenancePlanCreate) AddMaintenanceEntries(v ...*MaintenanceEntry) *MaintenancePlanCreate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddMaintenanceEntryIDs(ids...) +} + +// Mutation returns the MaintenancePlanMutation object of the builder. +func (_c *MaintenancePlanCreate) Mutation() *MaintenancePlanMutation { + return _c.mutation +} + +// Save creates the MaintenancePlan in the database. +func (_c *MaintenancePlanCreate) Save(ctx context.Context) (*MaintenancePlan, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *MaintenancePlanCreate) SaveX(ctx context.Context) *MaintenancePlan { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *MaintenancePlanCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *MaintenancePlanCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *MaintenancePlanCreate) defaults() { + if _, ok := _c.mutation.CreatedAt(); !ok { + v := maintenanceplan.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := maintenanceplan.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } + if _, ok := _c.mutation.Active(); !ok { + v := maintenanceplan.DefaultActive + _c.mutation.SetActive(v) + } + if _, ok := _c.mutation.ID(); !ok { + v := maintenanceplan.DefaultID() + _c.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *MaintenancePlanCreate) check() error { + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "MaintenancePlan.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "MaintenancePlan.updated_at"`)} + } + if _, ok := _c.mutation.EntityID(); !ok { + return &ValidationError{Name: "entity_id", err: errors.New(`ent: missing required field "MaintenancePlan.entity_id"`)} + } + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "MaintenancePlan.name"`)} + } + if v, ok := _c.mutation.Name(); ok { + if err := maintenanceplan.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.name": %w`, err)} + } + } + if v, ok := _c.mutation.Description(); ok { + if err := maintenanceplan.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.description": %w`, err)} + } + } + if _, ok := _c.mutation.IntervalValue(); !ok { + return &ValidationError{Name: "interval_value", err: errors.New(`ent: missing required field "MaintenancePlan.interval_value"`)} + } + if v, ok := _c.mutation.IntervalValue(); ok { + if err := maintenanceplan.IntervalValueValidator(v); err != nil { + return &ValidationError{Name: "interval_value", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_value": %w`, err)} + } + } + if _, ok := _c.mutation.IntervalUnit(); !ok { + return &ValidationError{Name: "interval_unit", err: errors.New(`ent: missing required field "MaintenancePlan.interval_unit"`)} + } + if v, ok := _c.mutation.IntervalUnit(); ok { + if err := maintenanceplan.IntervalUnitValidator(v); err != nil { + return &ValidationError{Name: "interval_unit", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_unit": %w`, err)} + } + } + if _, ok := _c.mutation.Active(); !ok { + return &ValidationError{Name: "active", err: errors.New(`ent: missing required field "MaintenancePlan.active"`)} + } + if len(_c.mutation.EntityIDs()) == 0 { + return &ValidationError{Name: "entity", err: errors.New(`ent: missing required edge "MaintenancePlan.entity"`)} + } + return nil +} + +func (_c *MaintenancePlanCreate) sqlSave(ctx context.Context) (*MaintenancePlan, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(*uuid.UUID); ok { + _node.ID = *id + } else if err := _node.ID.Scan(_spec.ID.Value); err != nil { + return nil, err + } + } + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *MaintenancePlanCreate) createSpec() (*MaintenancePlan, *sqlgraph.CreateSpec) { + var ( + _node = &MaintenancePlan{config: _c.config} + _spec = sqlgraph.NewCreateSpec(maintenanceplan.Table, sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID)) + ) + if id, ok := _c.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = &id + } + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(maintenanceplan.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(maintenanceplan.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(maintenanceplan.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Description(); ok { + _spec.SetField(maintenanceplan.FieldDescription, field.TypeString, value) + _node.Description = value + } + if value, ok := _c.mutation.IntervalValue(); ok { + _spec.SetField(maintenanceplan.FieldIntervalValue, field.TypeInt, value) + _node.IntervalValue = value + } + if value, ok := _c.mutation.IntervalUnit(); ok { + _spec.SetField(maintenanceplan.FieldIntervalUnit, field.TypeEnum, value) + _node.IntervalUnit = value + } + if value, ok := _c.mutation.Active(); ok { + _spec.SetField(maintenanceplan.FieldActive, field.TypeBool, value) + _node.Active = value + } + if value, ok := _c.mutation.LastCompletedAt(); ok { + _spec.SetField(maintenanceplan.FieldLastCompletedAt, field.TypeTime, value) + _node.LastCompletedAt = &value + } + if value, ok := _c.mutation.NextDueAt(); ok { + _spec.SetField(maintenanceplan.FieldNextDueAt, field.TypeTime, value) + _node.NextDueAt = &value + } + if nodes := _c.mutation.EntityIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceplan.EntityTable, + Columns: []string{maintenanceplan.EntityColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(entity.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.EntityID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := _c.mutation.MaintenanceEntriesIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// MaintenancePlanCreateBulk is the builder for creating many MaintenancePlan entities in bulk. +type MaintenancePlanCreateBulk struct { + config + err error + builders []*MaintenancePlanCreate +} + +// Save creates the MaintenancePlan entities in the database. +func (_c *MaintenancePlanCreateBulk) Save(ctx context.Context) ([]*MaintenancePlan, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*MaintenancePlan, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*MaintenancePlanMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *MaintenancePlanCreateBulk) SaveX(ctx context.Context) []*MaintenancePlan { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *MaintenancePlanCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *MaintenancePlanCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/internal/data/ent/maintenanceplan_delete.go b/backend/internal/data/ent/maintenanceplan_delete.go new file mode 100644 index 000000000..fc83d8bc6 --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" +) + +// MaintenancePlanDelete is the builder for deleting a MaintenancePlan entity. +type MaintenancePlanDelete struct { + config + hooks []Hook + mutation *MaintenancePlanMutation +} + +// Where appends a list predicates to the MaintenancePlanDelete builder. +func (_d *MaintenancePlanDelete) Where(ps ...predicate.MaintenancePlan) *MaintenancePlanDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *MaintenancePlanDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *MaintenancePlanDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *MaintenancePlanDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(maintenanceplan.Table, sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// MaintenancePlanDeleteOne is the builder for deleting a single MaintenancePlan entity. +type MaintenancePlanDeleteOne struct { + _d *MaintenancePlanDelete +} + +// Where appends a list predicates to the MaintenancePlanDelete builder. +func (_d *MaintenancePlanDeleteOne) Where(ps ...predicate.MaintenancePlan) *MaintenancePlanDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *MaintenancePlanDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{maintenanceplan.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *MaintenancePlanDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/internal/data/ent/maintenanceplan_query.go b/backend/internal/data/ent/maintenanceplan_query.go new file mode 100644 index 000000000..17b4976d3 --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan_query.go @@ -0,0 +1,687 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" +) + +// MaintenancePlanQuery is the builder for querying MaintenancePlan entities. +type MaintenancePlanQuery struct { + config + ctx *QueryContext + order []maintenanceplan.OrderOption + inters []Interceptor + predicates []predicate.MaintenancePlan + withEntity *EntityQuery + withMaintenanceEntries *MaintenanceEntryQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the MaintenancePlanQuery builder. +func (_q *MaintenancePlanQuery) Where(ps ...predicate.MaintenancePlan) *MaintenancePlanQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *MaintenancePlanQuery) Limit(limit int) *MaintenancePlanQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *MaintenancePlanQuery) Offset(offset int) *MaintenancePlanQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *MaintenancePlanQuery) Unique(unique bool) *MaintenancePlanQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *MaintenancePlanQuery) Order(o ...maintenanceplan.OrderOption) *MaintenancePlanQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryEntity chains the current query on the "entity" edge. +func (_q *MaintenancePlanQuery) QueryEntity() *EntityQuery { + query := (&EntityClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceplan.Table, maintenanceplan.FieldID, selector), + sqlgraph.To(entity.Table, entity.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, maintenanceplan.EntityTable, maintenanceplan.EntityColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryMaintenanceEntries chains the current query on the "maintenance_entries" edge. +func (_q *MaintenancePlanQuery) QueryMaintenanceEntries() *MaintenanceEntryQuery { + query := (&MaintenanceEntryClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(maintenanceplan.Table, maintenanceplan.FieldID, selector), + sqlgraph.To(maintenanceentry.Table, maintenanceentry.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, maintenanceplan.MaintenanceEntriesTable, maintenanceplan.MaintenanceEntriesColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first MaintenancePlan entity from the query. +// Returns a *NotFoundError when no MaintenancePlan was found. +func (_q *MaintenancePlanQuery) First(ctx context.Context) (*MaintenancePlan, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{maintenanceplan.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *MaintenancePlanQuery) FirstX(ctx context.Context) *MaintenancePlan { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first MaintenancePlan ID from the query. +// Returns a *NotFoundError when no MaintenancePlan ID was found. +func (_q *MaintenancePlanQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{maintenanceplan.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *MaintenancePlanQuery) FirstIDX(ctx context.Context) uuid.UUID { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single MaintenancePlan entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one MaintenancePlan entity is found. +// Returns a *NotFoundError when no MaintenancePlan entities are found. +func (_q *MaintenancePlanQuery) Only(ctx context.Context) (*MaintenancePlan, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{maintenanceplan.Label} + default: + return nil, &NotSingularError{maintenanceplan.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *MaintenancePlanQuery) OnlyX(ctx context.Context) *MaintenancePlan { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only MaintenancePlan ID in the query. +// Returns a *NotSingularError when more than one MaintenancePlan ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *MaintenancePlanQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{maintenanceplan.Label} + default: + err = &NotSingularError{maintenanceplan.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *MaintenancePlanQuery) OnlyIDX(ctx context.Context) uuid.UUID { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of MaintenancePlans. +func (_q *MaintenancePlanQuery) All(ctx context.Context) ([]*MaintenancePlan, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*MaintenancePlan, *MaintenancePlanQuery]() + return withInterceptors[[]*MaintenancePlan](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *MaintenancePlanQuery) AllX(ctx context.Context) []*MaintenancePlan { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of MaintenancePlan IDs. +func (_q *MaintenancePlanQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(maintenanceplan.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *MaintenancePlanQuery) IDsX(ctx context.Context) []uuid.UUID { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *MaintenancePlanQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*MaintenancePlanQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *MaintenancePlanQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *MaintenancePlanQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *MaintenancePlanQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the MaintenancePlanQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *MaintenancePlanQuery) Clone() *MaintenancePlanQuery { + if _q == nil { + return nil + } + return &MaintenancePlanQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]maintenanceplan.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.MaintenancePlan{}, _q.predicates...), + withEntity: _q.withEntity.Clone(), + withMaintenanceEntries: _q.withMaintenanceEntries.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithEntity tells the query-builder to eager-load the nodes that are connected to +// the "entity" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *MaintenancePlanQuery) WithEntity(opts ...func(*EntityQuery)) *MaintenancePlanQuery { + query := (&EntityClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withEntity = query + return _q +} + +// WithMaintenanceEntries tells the query-builder to eager-load the nodes that are connected to +// the "maintenance_entries" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *MaintenancePlanQuery) WithMaintenanceEntries(opts ...func(*MaintenanceEntryQuery)) *MaintenancePlanQuery { + query := (&MaintenanceEntryClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMaintenanceEntries = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.MaintenancePlan.Query(). +// GroupBy(maintenanceplan.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *MaintenancePlanQuery) GroupBy(field string, fields ...string) *MaintenancePlanGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &MaintenancePlanGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = maintenanceplan.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.MaintenancePlan.Query(). +// Select(maintenanceplan.FieldCreatedAt). +// Scan(ctx, &v) +func (_q *MaintenancePlanQuery) Select(fields ...string) *MaintenancePlanSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &MaintenancePlanSelect{MaintenancePlanQuery: _q} + sbuild.label = maintenanceplan.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a MaintenancePlanSelect configured with the given aggregations. +func (_q *MaintenancePlanQuery) Aggregate(fns ...AggregateFunc) *MaintenancePlanSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *MaintenancePlanQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !maintenanceplan.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *MaintenancePlanQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*MaintenancePlan, error) { + var ( + nodes = []*MaintenancePlan{} + _spec = _q.querySpec() + loadedTypes = [2]bool{ + _q.withEntity != nil, + _q.withMaintenanceEntries != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*MaintenancePlan).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &MaintenancePlan{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := _q.withEntity; query != nil { + if err := _q.loadEntity(ctx, query, nodes, nil, + func(n *MaintenancePlan, e *Entity) { n.Edges.Entity = e }); err != nil { + return nil, err + } + } + if query := _q.withMaintenanceEntries; query != nil { + if err := _q.loadMaintenanceEntries(ctx, query, nodes, + func(n *MaintenancePlan) { n.Edges.MaintenanceEntries = []*MaintenanceEntry{} }, + func(n *MaintenancePlan, e *MaintenanceEntry) { + n.Edges.MaintenanceEntries = append(n.Edges.MaintenanceEntries, e) + }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *MaintenancePlanQuery) loadEntity(ctx context.Context, query *EntityQuery, nodes []*MaintenancePlan, init func(*MaintenancePlan), assign func(*MaintenancePlan, *Entity)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*MaintenancePlan) + for i := range nodes { + fk := nodes[i].EntityID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(entity.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "entity_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (_q *MaintenancePlanQuery) loadMaintenanceEntries(ctx context.Context, query *MaintenanceEntryQuery, nodes []*MaintenancePlan, init func(*MaintenancePlan), assign func(*MaintenancePlan, *MaintenanceEntry)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[uuid.UUID]*MaintenancePlan) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(maintenanceentry.FieldPlanID) + } + query.Where(predicate.MaintenanceEntry(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(maintenanceplan.MaintenanceEntriesColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.PlanID + if fk == nil { + return fmt.Errorf(`foreign-key "plan_id" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "plan_id" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (_q *MaintenancePlanQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *MaintenancePlanQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(maintenanceplan.Table, maintenanceplan.Columns, sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, maintenanceplan.FieldID) + for i := range fields { + if fields[i] != maintenanceplan.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if _q.withEntity != nil { + _spec.Node.AddColumnOnce(maintenanceplan.FieldEntityID) + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *MaintenancePlanQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(maintenanceplan.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = maintenanceplan.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// MaintenancePlanGroupBy is the group-by builder for MaintenancePlan entities. +type MaintenancePlanGroupBy struct { + selector + build *MaintenancePlanQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *MaintenancePlanGroupBy) Aggregate(fns ...AggregateFunc) *MaintenancePlanGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *MaintenancePlanGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*MaintenancePlanQuery, *MaintenancePlanGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *MaintenancePlanGroupBy) sqlScan(ctx context.Context, root *MaintenancePlanQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// MaintenancePlanSelect is the builder for selecting fields of MaintenancePlan entities. +type MaintenancePlanSelect struct { + *MaintenancePlanQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *MaintenancePlanSelect) Aggregate(fns ...AggregateFunc) *MaintenancePlanSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *MaintenancePlanSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*MaintenancePlanQuery, *MaintenancePlanSelect](ctx, _s.MaintenancePlanQuery, _s, _s.inters, v) +} + +func (_s *MaintenancePlanSelect) sqlScan(ctx context.Context, root *MaintenancePlanQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/internal/data/ent/maintenanceplan_update.go b/backend/internal/data/ent/maintenanceplan_update.go new file mode 100644 index 000000000..c1827acfa --- /dev/null +++ b/backend/internal/data/ent/maintenanceplan_update.go @@ -0,0 +1,859 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" +) + +// MaintenancePlanUpdate is the builder for updating MaintenancePlan entities. +type MaintenancePlanUpdate struct { + config + hooks []Hook + mutation *MaintenancePlanMutation +} + +// Where appends a list predicates to the MaintenancePlanUpdate builder. +func (_u *MaintenancePlanUpdate) Where(ps ...predicate.MaintenancePlan) *MaintenancePlanUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *MaintenancePlanUpdate) SetUpdatedAt(v time.Time) *MaintenancePlanUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetEntityID sets the "entity_id" field. +func (_u *MaintenancePlanUpdate) SetEntityID(v uuid.UUID) *MaintenancePlanUpdate { + _u.mutation.SetEntityID(v) + return _u +} + +// SetNillableEntityID sets the "entity_id" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableEntityID(v *uuid.UUID) *MaintenancePlanUpdate { + if v != nil { + _u.SetEntityID(*v) + } + return _u +} + +// SetName sets the "name" field. +func (_u *MaintenancePlanUpdate) SetName(v string) *MaintenancePlanUpdate { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableName(v *string) *MaintenancePlanUpdate { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *MaintenancePlanUpdate) SetDescription(v string) *MaintenancePlanUpdate { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableDescription(v *string) *MaintenancePlanUpdate { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *MaintenancePlanUpdate) ClearDescription() *MaintenancePlanUpdate { + _u.mutation.ClearDescription() + return _u +} + +// SetIntervalValue sets the "interval_value" field. +func (_u *MaintenancePlanUpdate) SetIntervalValue(v int) *MaintenancePlanUpdate { + _u.mutation.ResetIntervalValue() + _u.mutation.SetIntervalValue(v) + return _u +} + +// SetNillableIntervalValue sets the "interval_value" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableIntervalValue(v *int) *MaintenancePlanUpdate { + if v != nil { + _u.SetIntervalValue(*v) + } + return _u +} + +// AddIntervalValue adds value to the "interval_value" field. +func (_u *MaintenancePlanUpdate) AddIntervalValue(v int) *MaintenancePlanUpdate { + _u.mutation.AddIntervalValue(v) + return _u +} + +// SetIntervalUnit sets the "interval_unit" field. +func (_u *MaintenancePlanUpdate) SetIntervalUnit(v maintenanceplan.IntervalUnit) *MaintenancePlanUpdate { + _u.mutation.SetIntervalUnit(v) + return _u +} + +// SetNillableIntervalUnit sets the "interval_unit" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableIntervalUnit(v *maintenanceplan.IntervalUnit) *MaintenancePlanUpdate { + if v != nil { + _u.SetIntervalUnit(*v) + } + return _u +} + +// SetActive sets the "active" field. +func (_u *MaintenancePlanUpdate) SetActive(v bool) *MaintenancePlanUpdate { + _u.mutation.SetActive(v) + return _u +} + +// SetNillableActive sets the "active" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableActive(v *bool) *MaintenancePlanUpdate { + if v != nil { + _u.SetActive(*v) + } + return _u +} + +// SetLastCompletedAt sets the "last_completed_at" field. +func (_u *MaintenancePlanUpdate) SetLastCompletedAt(v time.Time) *MaintenancePlanUpdate { + _u.mutation.SetLastCompletedAt(v) + return _u +} + +// SetNillableLastCompletedAt sets the "last_completed_at" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableLastCompletedAt(v *time.Time) *MaintenancePlanUpdate { + if v != nil { + _u.SetLastCompletedAt(*v) + } + return _u +} + +// ClearLastCompletedAt clears the value of the "last_completed_at" field. +func (_u *MaintenancePlanUpdate) ClearLastCompletedAt() *MaintenancePlanUpdate { + _u.mutation.ClearLastCompletedAt() + return _u +} + +// SetNextDueAt sets the "next_due_at" field. +func (_u *MaintenancePlanUpdate) SetNextDueAt(v time.Time) *MaintenancePlanUpdate { + _u.mutation.SetNextDueAt(v) + return _u +} + +// SetNillableNextDueAt sets the "next_due_at" field if the given value is not nil. +func (_u *MaintenancePlanUpdate) SetNillableNextDueAt(v *time.Time) *MaintenancePlanUpdate { + if v != nil { + _u.SetNextDueAt(*v) + } + return _u +} + +// ClearNextDueAt clears the value of the "next_due_at" field. +func (_u *MaintenancePlanUpdate) ClearNextDueAt() *MaintenancePlanUpdate { + _u.mutation.ClearNextDueAt() + return _u +} + +// SetEntity sets the "entity" edge to the Entity entity. +func (_u *MaintenancePlanUpdate) SetEntity(v *Entity) *MaintenancePlanUpdate { + return _u.SetEntityID(v.ID) +} + +// AddMaintenanceEntryIDs adds the "maintenance_entries" edge to the MaintenanceEntry entity by IDs. +func (_u *MaintenancePlanUpdate) AddMaintenanceEntryIDs(ids ...uuid.UUID) *MaintenancePlanUpdate { + _u.mutation.AddMaintenanceEntryIDs(ids...) + return _u +} + +// AddMaintenanceEntries adds the "maintenance_entries" edges to the MaintenanceEntry entity. +func (_u *MaintenancePlanUpdate) AddMaintenanceEntries(v ...*MaintenanceEntry) *MaintenancePlanUpdate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMaintenanceEntryIDs(ids...) +} + +// Mutation returns the MaintenancePlanMutation object of the builder. +func (_u *MaintenancePlanUpdate) Mutation() *MaintenancePlanMutation { + return _u.mutation +} + +// ClearEntity clears the "entity" edge to the Entity entity. +func (_u *MaintenancePlanUpdate) ClearEntity() *MaintenancePlanUpdate { + _u.mutation.ClearEntity() + return _u +} + +// ClearMaintenanceEntries clears all "maintenance_entries" edges to the MaintenanceEntry entity. +func (_u *MaintenancePlanUpdate) ClearMaintenanceEntries() *MaintenancePlanUpdate { + _u.mutation.ClearMaintenanceEntries() + return _u +} + +// RemoveMaintenanceEntryIDs removes the "maintenance_entries" edge to MaintenanceEntry entities by IDs. +func (_u *MaintenancePlanUpdate) RemoveMaintenanceEntryIDs(ids ...uuid.UUID) *MaintenancePlanUpdate { + _u.mutation.RemoveMaintenanceEntryIDs(ids...) + return _u +} + +// RemoveMaintenanceEntries removes "maintenance_entries" edges to MaintenanceEntry entities. +func (_u *MaintenancePlanUpdate) RemoveMaintenanceEntries(v ...*MaintenanceEntry) *MaintenancePlanUpdate { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMaintenanceEntryIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *MaintenancePlanUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *MaintenancePlanUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *MaintenancePlanUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *MaintenancePlanUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *MaintenancePlanUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := maintenanceplan.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *MaintenancePlanUpdate) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := maintenanceplan.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.name": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := maintenanceplan.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.description": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalValue(); ok { + if err := maintenanceplan.IntervalValueValidator(v); err != nil { + return &ValidationError{Name: "interval_value", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_value": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalUnit(); ok { + if err := maintenanceplan.IntervalUnitValidator(v); err != nil { + return &ValidationError{Name: "interval_unit", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_unit": %w`, err)} + } + } + if _u.mutation.EntityCleared() && len(_u.mutation.EntityIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "MaintenancePlan.entity"`) + } + return nil +} + +func (_u *MaintenancePlanUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(maintenanceplan.Table, maintenanceplan.Columns, sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(maintenanceplan.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(maintenanceplan.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(maintenanceplan.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(maintenanceplan.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.IntervalValue(); ok { + _spec.SetField(maintenanceplan.FieldIntervalValue, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedIntervalValue(); ok { + _spec.AddField(maintenanceplan.FieldIntervalValue, field.TypeInt, value) + } + if value, ok := _u.mutation.IntervalUnit(); ok { + _spec.SetField(maintenanceplan.FieldIntervalUnit, field.TypeEnum, value) + } + if value, ok := _u.mutation.Active(); ok { + _spec.SetField(maintenanceplan.FieldActive, field.TypeBool, value) + } + if value, ok := _u.mutation.LastCompletedAt(); ok { + _spec.SetField(maintenanceplan.FieldLastCompletedAt, field.TypeTime, value) + } + if _u.mutation.LastCompletedAtCleared() { + _spec.ClearField(maintenanceplan.FieldLastCompletedAt, field.TypeTime) + } + if value, ok := _u.mutation.NextDueAt(); ok { + _spec.SetField(maintenanceplan.FieldNextDueAt, field.TypeTime, value) + } + if _u.mutation.NextDueAtCleared() { + _spec.ClearField(maintenanceplan.FieldNextDueAt, field.TypeTime) + } + if _u.mutation.EntityCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceplan.EntityTable, + Columns: []string{maintenanceplan.EntityColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(entity.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.EntityIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceplan.EntityTable, + Columns: []string{maintenanceplan.EntityColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(entity.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.MaintenanceEntriesCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMaintenanceEntriesIDs(); len(nodes) > 0 && !_u.mutation.MaintenanceEntriesCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MaintenanceEntriesIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{maintenanceplan.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// MaintenancePlanUpdateOne is the builder for updating a single MaintenancePlan entity. +type MaintenancePlanUpdateOne struct { + config + fields []string + hooks []Hook + mutation *MaintenancePlanMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *MaintenancePlanUpdateOne) SetUpdatedAt(v time.Time) *MaintenancePlanUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetEntityID sets the "entity_id" field. +func (_u *MaintenancePlanUpdateOne) SetEntityID(v uuid.UUID) *MaintenancePlanUpdateOne { + _u.mutation.SetEntityID(v) + return _u +} + +// SetNillableEntityID sets the "entity_id" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableEntityID(v *uuid.UUID) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetEntityID(*v) + } + return _u +} + +// SetName sets the "name" field. +func (_u *MaintenancePlanUpdateOne) SetName(v string) *MaintenancePlanUpdateOne { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableName(v *string) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *MaintenancePlanUpdateOne) SetDescription(v string) *MaintenancePlanUpdateOne { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableDescription(v *string) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *MaintenancePlanUpdateOne) ClearDescription() *MaintenancePlanUpdateOne { + _u.mutation.ClearDescription() + return _u +} + +// SetIntervalValue sets the "interval_value" field. +func (_u *MaintenancePlanUpdateOne) SetIntervalValue(v int) *MaintenancePlanUpdateOne { + _u.mutation.ResetIntervalValue() + _u.mutation.SetIntervalValue(v) + return _u +} + +// SetNillableIntervalValue sets the "interval_value" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableIntervalValue(v *int) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetIntervalValue(*v) + } + return _u +} + +// AddIntervalValue adds value to the "interval_value" field. +func (_u *MaintenancePlanUpdateOne) AddIntervalValue(v int) *MaintenancePlanUpdateOne { + _u.mutation.AddIntervalValue(v) + return _u +} + +// SetIntervalUnit sets the "interval_unit" field. +func (_u *MaintenancePlanUpdateOne) SetIntervalUnit(v maintenanceplan.IntervalUnit) *MaintenancePlanUpdateOne { + _u.mutation.SetIntervalUnit(v) + return _u +} + +// SetNillableIntervalUnit sets the "interval_unit" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableIntervalUnit(v *maintenanceplan.IntervalUnit) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetIntervalUnit(*v) + } + return _u +} + +// SetActive sets the "active" field. +func (_u *MaintenancePlanUpdateOne) SetActive(v bool) *MaintenancePlanUpdateOne { + _u.mutation.SetActive(v) + return _u +} + +// SetNillableActive sets the "active" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableActive(v *bool) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetActive(*v) + } + return _u +} + +// SetLastCompletedAt sets the "last_completed_at" field. +func (_u *MaintenancePlanUpdateOne) SetLastCompletedAt(v time.Time) *MaintenancePlanUpdateOne { + _u.mutation.SetLastCompletedAt(v) + return _u +} + +// SetNillableLastCompletedAt sets the "last_completed_at" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableLastCompletedAt(v *time.Time) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetLastCompletedAt(*v) + } + return _u +} + +// ClearLastCompletedAt clears the value of the "last_completed_at" field. +func (_u *MaintenancePlanUpdateOne) ClearLastCompletedAt() *MaintenancePlanUpdateOne { + _u.mutation.ClearLastCompletedAt() + return _u +} + +// SetNextDueAt sets the "next_due_at" field. +func (_u *MaintenancePlanUpdateOne) SetNextDueAt(v time.Time) *MaintenancePlanUpdateOne { + _u.mutation.SetNextDueAt(v) + return _u +} + +// SetNillableNextDueAt sets the "next_due_at" field if the given value is not nil. +func (_u *MaintenancePlanUpdateOne) SetNillableNextDueAt(v *time.Time) *MaintenancePlanUpdateOne { + if v != nil { + _u.SetNextDueAt(*v) + } + return _u +} + +// ClearNextDueAt clears the value of the "next_due_at" field. +func (_u *MaintenancePlanUpdateOne) ClearNextDueAt() *MaintenancePlanUpdateOne { + _u.mutation.ClearNextDueAt() + return _u +} + +// SetEntity sets the "entity" edge to the Entity entity. +func (_u *MaintenancePlanUpdateOne) SetEntity(v *Entity) *MaintenancePlanUpdateOne { + return _u.SetEntityID(v.ID) +} + +// AddMaintenanceEntryIDs adds the "maintenance_entries" edge to the MaintenanceEntry entity by IDs. +func (_u *MaintenancePlanUpdateOne) AddMaintenanceEntryIDs(ids ...uuid.UUID) *MaintenancePlanUpdateOne { + _u.mutation.AddMaintenanceEntryIDs(ids...) + return _u +} + +// AddMaintenanceEntries adds the "maintenance_entries" edges to the MaintenanceEntry entity. +func (_u *MaintenancePlanUpdateOne) AddMaintenanceEntries(v ...*MaintenanceEntry) *MaintenancePlanUpdateOne { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMaintenanceEntryIDs(ids...) +} + +// Mutation returns the MaintenancePlanMutation object of the builder. +func (_u *MaintenancePlanUpdateOne) Mutation() *MaintenancePlanMutation { + return _u.mutation +} + +// ClearEntity clears the "entity" edge to the Entity entity. +func (_u *MaintenancePlanUpdateOne) ClearEntity() *MaintenancePlanUpdateOne { + _u.mutation.ClearEntity() + return _u +} + +// ClearMaintenanceEntries clears all "maintenance_entries" edges to the MaintenanceEntry entity. +func (_u *MaintenancePlanUpdateOne) ClearMaintenanceEntries() *MaintenancePlanUpdateOne { + _u.mutation.ClearMaintenanceEntries() + return _u +} + +// RemoveMaintenanceEntryIDs removes the "maintenance_entries" edge to MaintenanceEntry entities by IDs. +func (_u *MaintenancePlanUpdateOne) RemoveMaintenanceEntryIDs(ids ...uuid.UUID) *MaintenancePlanUpdateOne { + _u.mutation.RemoveMaintenanceEntryIDs(ids...) + return _u +} + +// RemoveMaintenanceEntries removes "maintenance_entries" edges to MaintenanceEntry entities. +func (_u *MaintenancePlanUpdateOne) RemoveMaintenanceEntries(v ...*MaintenanceEntry) *MaintenancePlanUpdateOne { + ids := make([]uuid.UUID, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMaintenanceEntryIDs(ids...) +} + +// Where appends a list predicates to the MaintenancePlanUpdate builder. +func (_u *MaintenancePlanUpdateOne) Where(ps ...predicate.MaintenancePlan) *MaintenancePlanUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *MaintenancePlanUpdateOne) Select(field string, fields ...string) *MaintenancePlanUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated MaintenancePlan entity. +func (_u *MaintenancePlanUpdateOne) Save(ctx context.Context) (*MaintenancePlan, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *MaintenancePlanUpdateOne) SaveX(ctx context.Context) *MaintenancePlan { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *MaintenancePlanUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *MaintenancePlanUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *MaintenancePlanUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := maintenanceplan.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *MaintenancePlanUpdateOne) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := maintenanceplan.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.name": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := maintenanceplan.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.description": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalValue(); ok { + if err := maintenanceplan.IntervalValueValidator(v); err != nil { + return &ValidationError{Name: "interval_value", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_value": %w`, err)} + } + } + if v, ok := _u.mutation.IntervalUnit(); ok { + if err := maintenanceplan.IntervalUnitValidator(v); err != nil { + return &ValidationError{Name: "interval_unit", err: fmt.Errorf(`ent: validator failed for field "MaintenancePlan.interval_unit": %w`, err)} + } + } + if _u.mutation.EntityCleared() && len(_u.mutation.EntityIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "MaintenancePlan.entity"`) + } + return nil +} + +func (_u *MaintenancePlanUpdateOne) sqlSave(ctx context.Context) (_node *MaintenancePlan, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(maintenanceplan.Table, maintenanceplan.Columns, sqlgraph.NewFieldSpec(maintenanceplan.FieldID, field.TypeUUID)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "MaintenancePlan.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, maintenanceplan.FieldID) + for _, f := range fields { + if !maintenanceplan.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != maintenanceplan.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(maintenanceplan.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(maintenanceplan.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(maintenanceplan.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(maintenanceplan.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.IntervalValue(); ok { + _spec.SetField(maintenanceplan.FieldIntervalValue, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedIntervalValue(); ok { + _spec.AddField(maintenanceplan.FieldIntervalValue, field.TypeInt, value) + } + if value, ok := _u.mutation.IntervalUnit(); ok { + _spec.SetField(maintenanceplan.FieldIntervalUnit, field.TypeEnum, value) + } + if value, ok := _u.mutation.Active(); ok { + _spec.SetField(maintenanceplan.FieldActive, field.TypeBool, value) + } + if value, ok := _u.mutation.LastCompletedAt(); ok { + _spec.SetField(maintenanceplan.FieldLastCompletedAt, field.TypeTime, value) + } + if _u.mutation.LastCompletedAtCleared() { + _spec.ClearField(maintenanceplan.FieldLastCompletedAt, field.TypeTime) + } + if value, ok := _u.mutation.NextDueAt(); ok { + _spec.SetField(maintenanceplan.FieldNextDueAt, field.TypeTime, value) + } + if _u.mutation.NextDueAtCleared() { + _spec.ClearField(maintenanceplan.FieldNextDueAt, field.TypeTime) + } + if _u.mutation.EntityCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceplan.EntityTable, + Columns: []string{maintenanceplan.EntityColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(entity.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.EntityIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: maintenanceplan.EntityTable, + Columns: []string{maintenanceplan.EntityColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(entity.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _u.mutation.MaintenanceEntriesCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMaintenanceEntriesIDs(); len(nodes) > 0 && !_u.mutation.MaintenanceEntriesCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MaintenanceEntriesIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: maintenanceplan.MaintenanceEntriesTable, + Columns: []string{maintenanceplan.MaintenanceEntriesColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(maintenanceentry.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &MaintenancePlan{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{maintenanceplan.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/internal/data/ent/migrate/schema.go b/backend/internal/data/ent/migrate/schema.go index 47a900664..751108fb6 100644 --- a/backend/internal/data/ent/migrate/schema.go +++ b/backend/internal/data/ent/migrate/schema.go @@ -416,6 +416,7 @@ var ( {Name: "description", Type: field.TypeString, Nullable: true, Size: 2500}, {Name: "cost", Type: field.TypeFloat64, Default: 0}, {Name: "entity_id", Type: field.TypeUUID}, + {Name: "plan_id", Type: field.TypeUUID, Nullable: true}, } // MaintenanceEntriesTable holds the schema information for the "maintenance_entries" table. MaintenanceEntriesTable = &schema.Table{ @@ -429,6 +430,40 @@ var ( RefColumns: []*schema.Column{EntitiesColumns[0]}, OnDelete: schema.Cascade, }, + { + Symbol: "maintenance_entries_maintenance_plans_maintenance_entries", + Columns: []*schema.Column{MaintenanceEntriesColumns[9]}, + RefColumns: []*schema.Column{MaintenancePlansColumns[0]}, + OnDelete: schema.SetNull, + }, + }, + } + // MaintenancePlansColumns holds the columns for the "maintenance_plans" table. + MaintenancePlansColumns = []*schema.Column{ + {Name: "id", Type: field.TypeUUID}, + {Name: "created_at", Type: field.TypeTime}, + {Name: "updated_at", Type: field.TypeTime}, + {Name: "name", Type: field.TypeString, Size: 255}, + {Name: "description", Type: field.TypeString, Nullable: true, Size: 2500}, + {Name: "interval_value", Type: field.TypeInt}, + {Name: "interval_unit", Type: field.TypeEnum, Enums: []string{"hour", "day", "week", "month", "year"}}, + {Name: "active", Type: field.TypeBool, Default: true}, + {Name: "last_completed_at", Type: field.TypeTime, Nullable: true}, + {Name: "next_due_at", Type: field.TypeTime, Nullable: true}, + {Name: "entity_id", Type: field.TypeUUID}, + } + // MaintenancePlansTable holds the schema information for the "maintenance_plans" table. + MaintenancePlansTable = &schema.Table{ + Name: "maintenance_plans", + Columns: MaintenancePlansColumns, + PrimaryKey: []*schema.Column{MaintenancePlansColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "maintenance_plans_entities_maintenance_plans", + Columns: []*schema.Column{MaintenancePlansColumns[10]}, + RefColumns: []*schema.Column{EntitiesColumns[0]}, + OnDelete: schema.Cascade, + }, }, } // NotifiersColumns holds the columns for the "notifiers" table. @@ -669,6 +704,7 @@ var ( GroupsTable, GroupInvitationTokensTable, MaintenanceEntriesTable, + MaintenancePlansTable, NotifiersTable, PasswordResetTokensTable, TagsTable, @@ -696,6 +732,8 @@ func init() { ExportsTable.ForeignKeys[0].RefTable = GroupsTable GroupInvitationTokensTable.ForeignKeys[0].RefTable = GroupsTable MaintenanceEntriesTable.ForeignKeys[0].RefTable = EntitiesTable + MaintenanceEntriesTable.ForeignKeys[1].RefTable = MaintenancePlansTable + MaintenancePlansTable.ForeignKeys[0].RefTable = EntitiesTable NotifiersTable.ForeignKeys[0].RefTable = GroupsTable NotifiersTable.ForeignKeys[1].RefTable = UsersTable PasswordResetTokensTable.ForeignKeys[0].RefTable = UsersTable diff --git a/backend/internal/data/ent/mutation.go b/backend/internal/data/ent/mutation.go index 47ee02343..fbb6742e2 100644 --- a/backend/internal/data/ent/mutation.go +++ b/backend/internal/data/ent/mutation.go @@ -24,6 +24,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/groupinvitationtoken" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/notifier" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/passwordresettokens" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate" @@ -54,6 +55,7 @@ const ( TypeGroup = "Group" TypeGroupInvitationToken = "GroupInvitationToken" TypeMaintenanceEntry = "MaintenanceEntry" + TypeMaintenancePlan = "MaintenancePlan" TypeNotifier = "Notifier" TypePasswordResetTokens = "PasswordResetTokens" TypeTag = "Tag" @@ -2661,6 +2663,9 @@ type EntityMutation struct { maintenance_entries map[uuid.UUID]struct{} removedmaintenance_entries map[uuid.UUID]struct{} clearedmaintenance_entries bool + maintenance_plans map[uuid.UUID]struct{} + removedmaintenance_plans map[uuid.UUID]struct{} + clearedmaintenance_plans bool attachments map[uuid.UUID]struct{} removedattachments map[uuid.UUID]struct{} clearedattachments bool @@ -4219,6 +4224,60 @@ func (m *EntityMutation) ResetMaintenanceEntries() { m.removedmaintenance_entries = nil } +// AddMaintenancePlanIDs adds the "maintenance_plans" edge to the MaintenancePlan entity by ids. +func (m *EntityMutation) AddMaintenancePlanIDs(ids ...uuid.UUID) { + if m.maintenance_plans == nil { + m.maintenance_plans = make(map[uuid.UUID]struct{}) + } + for i := range ids { + m.maintenance_plans[ids[i]] = struct{}{} + } +} + +// ClearMaintenancePlans clears the "maintenance_plans" edge to the MaintenancePlan entity. +func (m *EntityMutation) ClearMaintenancePlans() { + m.clearedmaintenance_plans = true +} + +// MaintenancePlansCleared reports if the "maintenance_plans" edge to the MaintenancePlan entity was cleared. +func (m *EntityMutation) MaintenancePlansCleared() bool { + return m.clearedmaintenance_plans +} + +// RemoveMaintenancePlanIDs removes the "maintenance_plans" edge to the MaintenancePlan entity by IDs. +func (m *EntityMutation) RemoveMaintenancePlanIDs(ids ...uuid.UUID) { + if m.removedmaintenance_plans == nil { + m.removedmaintenance_plans = make(map[uuid.UUID]struct{}) + } + for i := range ids { + delete(m.maintenance_plans, ids[i]) + m.removedmaintenance_plans[ids[i]] = struct{}{} + } +} + +// RemovedMaintenancePlans returns the removed IDs of the "maintenance_plans" edge to the MaintenancePlan entity. +func (m *EntityMutation) RemovedMaintenancePlansIDs() (ids []uuid.UUID) { + for id := range m.removedmaintenance_plans { + ids = append(ids, id) + } + return +} + +// MaintenancePlansIDs returns the "maintenance_plans" edge IDs in the mutation. +func (m *EntityMutation) MaintenancePlansIDs() (ids []uuid.UUID) { + for id := range m.maintenance_plans { + ids = append(ids, id) + } + return +} + +// ResetMaintenancePlans resets all changes to the "maintenance_plans" edge. +func (m *EntityMutation) ResetMaintenancePlans() { + m.maintenance_plans = nil + m.clearedmaintenance_plans = false + m.removedmaintenance_plans = nil +} + // AddAttachmentIDs adds the "attachments" edge to the Attachment entity by ids. func (m *EntityMutation) AddAttachmentIDs(ids ...uuid.UUID) { if m.attachments == nil { @@ -4929,7 +4988,7 @@ func (m *EntityMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *EntityMutation) AddedEdges() []string { - edges := make([]string, 0, 8) + edges := make([]string, 0, 9) if m.group != nil { edges = append(edges, entity.EdgeGroup) } @@ -4951,6 +5010,9 @@ func (m *EntityMutation) AddedEdges() []string { if m.maintenance_entries != nil { edges = append(edges, entity.EdgeMaintenanceEntries) } + if m.maintenance_plans != nil { + edges = append(edges, entity.EdgeMaintenancePlans) + } if m.attachments != nil { edges = append(edges, entity.EdgeAttachments) } @@ -4997,6 +5059,12 @@ func (m *EntityMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case entity.EdgeMaintenancePlans: + ids := make([]ent.Value, 0, len(m.maintenance_plans)) + for id := range m.maintenance_plans { + ids = append(ids, id) + } + return ids case entity.EdgeAttachments: ids := make([]ent.Value, 0, len(m.attachments)) for id := range m.attachments { @@ -5009,7 +5077,7 @@ func (m *EntityMutation) AddedIDs(name string) []ent.Value { // RemovedEdges returns all edge names that were removed in this mutation. func (m *EntityMutation) RemovedEdges() []string { - edges := make([]string, 0, 8) + edges := make([]string, 0, 9) if m.removedchildren != nil { edges = append(edges, entity.EdgeChildren) } @@ -5022,6 +5090,9 @@ func (m *EntityMutation) RemovedEdges() []string { if m.removedmaintenance_entries != nil { edges = append(edges, entity.EdgeMaintenanceEntries) } + if m.removedmaintenance_plans != nil { + edges = append(edges, entity.EdgeMaintenancePlans) + } if m.removedattachments != nil { edges = append(edges, entity.EdgeAttachments) } @@ -5056,6 +5127,12 @@ func (m *EntityMutation) RemovedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case entity.EdgeMaintenancePlans: + ids := make([]ent.Value, 0, len(m.removedmaintenance_plans)) + for id := range m.removedmaintenance_plans { + ids = append(ids, id) + } + return ids case entity.EdgeAttachments: ids := make([]ent.Value, 0, len(m.removedattachments)) for id := range m.removedattachments { @@ -5068,7 +5145,7 @@ func (m *EntityMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *EntityMutation) ClearedEdges() []string { - edges := make([]string, 0, 8) + edges := make([]string, 0, 9) if m.clearedgroup { edges = append(edges, entity.EdgeGroup) } @@ -5090,6 +5167,9 @@ func (m *EntityMutation) ClearedEdges() []string { if m.clearedmaintenance_entries { edges = append(edges, entity.EdgeMaintenanceEntries) } + if m.clearedmaintenance_plans { + edges = append(edges, entity.EdgeMaintenancePlans) + } if m.clearedattachments { edges = append(edges, entity.EdgeAttachments) } @@ -5114,6 +5194,8 @@ func (m *EntityMutation) EdgeCleared(name string) bool { return m.clearedfields case entity.EdgeMaintenanceEntries: return m.clearedmaintenance_entries + case entity.EdgeMaintenancePlans: + return m.clearedmaintenance_plans case entity.EdgeAttachments: return m.clearedattachments } @@ -5162,6 +5244,9 @@ func (m *EntityMutation) ResetEdge(name string) error { case entity.EdgeMaintenanceEntries: m.ResetMaintenanceEntries() return nil + case entity.EdgeMaintenancePlans: + m.ResetMaintenancePlans() + return nil case entity.EdgeAttachments: m.ResetAttachments() return nil @@ -11330,6 +11415,8 @@ type MaintenanceEntryMutation struct { clearedFields map[string]struct{} entity *uuid.UUID clearedentity bool + plan *uuid.UUID + clearedplan bool done bool oldValue func(context.Context) (*MaintenanceEntry, error) predicates []predicate.MaintenanceEntry @@ -11547,6 +11634,55 @@ func (m *MaintenanceEntryMutation) ResetEntityID() { m.entity = nil } +// SetPlanID sets the "plan_id" field. +func (m *MaintenanceEntryMutation) SetPlanID(u uuid.UUID) { + m.plan = &u +} + +// PlanID returns the value of the "plan_id" field in the mutation. +func (m *MaintenanceEntryMutation) PlanID() (r uuid.UUID, exists bool) { + v := m.plan + if v == nil { + return + } + return *v, true +} + +// OldPlanID returns the old "plan_id" field's value of the MaintenanceEntry entity. +// If the MaintenanceEntry object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenanceEntryMutation) OldPlanID(ctx context.Context) (v *uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPlanID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPlanID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPlanID: %w", err) + } + return oldValue.PlanID, nil +} + +// ClearPlanID clears the value of the "plan_id" field. +func (m *MaintenanceEntryMutation) ClearPlanID() { + m.plan = nil + m.clearedFields[maintenanceentry.FieldPlanID] = struct{}{} +} + +// PlanIDCleared returns if the "plan_id" field was cleared in this mutation. +func (m *MaintenanceEntryMutation) PlanIDCleared() bool { + _, ok := m.clearedFields[maintenanceentry.FieldPlanID] + return ok +} + +// ResetPlanID resets all changes to the "plan_id" field. +func (m *MaintenanceEntryMutation) ResetPlanID() { + m.plan = nil + delete(m.clearedFields, maintenanceentry.FieldPlanID) +} + // SetDate sets the "date" field. func (m *MaintenanceEntryMutation) SetDate(t time.Time) { m.date = &t @@ -11813,6 +11949,33 @@ func (m *MaintenanceEntryMutation) ResetEntity() { m.clearedentity = false } +// ClearPlan clears the "plan" edge to the MaintenancePlan entity. +func (m *MaintenanceEntryMutation) ClearPlan() { + m.clearedplan = true + m.clearedFields[maintenanceentry.FieldPlanID] = struct{}{} +} + +// PlanCleared reports if the "plan" edge to the MaintenancePlan entity was cleared. +func (m *MaintenanceEntryMutation) PlanCleared() bool { + return m.PlanIDCleared() || m.clearedplan +} + +// PlanIDs returns the "plan" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// PlanID instead. It exists only for internal usage by the builders. +func (m *MaintenanceEntryMutation) PlanIDs() (ids []uuid.UUID) { + if id := m.plan; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetPlan resets all changes to the "plan" edge. +func (m *MaintenanceEntryMutation) ResetPlan() { + m.plan = nil + m.clearedplan = false +} + // Where appends a list predicates to the MaintenanceEntryMutation builder. func (m *MaintenanceEntryMutation) Where(ps ...predicate.MaintenanceEntry) { m.predicates = append(m.predicates, ps...) @@ -11847,7 +12010,7 @@ func (m *MaintenanceEntryMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *MaintenanceEntryMutation) Fields() []string { - fields := make([]string, 0, 8) + fields := make([]string, 0, 9) if m.created_at != nil { fields = append(fields, maintenanceentry.FieldCreatedAt) } @@ -11857,6 +12020,9 @@ func (m *MaintenanceEntryMutation) Fields() []string { if m.entity != nil { fields = append(fields, maintenanceentry.FieldEntityID) } + if m.plan != nil { + fields = append(fields, maintenanceentry.FieldPlanID) + } if m.date != nil { fields = append(fields, maintenanceentry.FieldDate) } @@ -11886,6 +12052,8 @@ func (m *MaintenanceEntryMutation) Field(name string) (ent.Value, bool) { return m.UpdatedAt() case maintenanceentry.FieldEntityID: return m.EntityID() + case maintenanceentry.FieldPlanID: + return m.PlanID() case maintenanceentry.FieldDate: return m.Date() case maintenanceentry.FieldScheduledDate: @@ -11911,6 +12079,8 @@ func (m *MaintenanceEntryMutation) OldField(ctx context.Context, name string) (e return m.OldUpdatedAt(ctx) case maintenanceentry.FieldEntityID: return m.OldEntityID(ctx) + case maintenanceentry.FieldPlanID: + return m.OldPlanID(ctx) case maintenanceentry.FieldDate: return m.OldDate(ctx) case maintenanceentry.FieldScheduledDate: @@ -11951,6 +12121,13 @@ func (m *MaintenanceEntryMutation) SetField(name string, value ent.Value) error } m.SetEntityID(v) return nil + case maintenanceentry.FieldPlanID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPlanID(v) + return nil case maintenanceentry.FieldDate: v, ok := value.(time.Time) if !ok { @@ -12031,6 +12208,9 @@ func (m *MaintenanceEntryMutation) AddField(name string, value ent.Value) error // mutation. func (m *MaintenanceEntryMutation) ClearedFields() []string { var fields []string + if m.FieldCleared(maintenanceentry.FieldPlanID) { + fields = append(fields, maintenanceentry.FieldPlanID) + } if m.FieldCleared(maintenanceentry.FieldDate) { fields = append(fields, maintenanceentry.FieldDate) } @@ -12054,6 +12234,9 @@ func (m *MaintenanceEntryMutation) FieldCleared(name string) bool { // error if the field is not defined in the schema. func (m *MaintenanceEntryMutation) ClearField(name string) error { switch name { + case maintenanceentry.FieldPlanID: + m.ClearPlanID() + return nil case maintenanceentry.FieldDate: m.ClearDate() return nil @@ -12080,6 +12263,9 @@ func (m *MaintenanceEntryMutation) ResetField(name string) error { case maintenanceentry.FieldEntityID: m.ResetEntityID() return nil + case maintenanceentry.FieldPlanID: + m.ResetPlanID() + return nil case maintenanceentry.FieldDate: m.ResetDate() return nil @@ -12101,10 +12287,13 @@ func (m *MaintenanceEntryMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *MaintenanceEntryMutation) AddedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) if m.entity != nil { edges = append(edges, maintenanceentry.EdgeEntity) } + if m.plan != nil { + edges = append(edges, maintenanceentry.EdgePlan) + } return edges } @@ -12116,13 +12305,17 @@ func (m *MaintenanceEntryMutation) AddedIDs(name string) []ent.Value { if id := m.entity; id != nil { return []ent.Value{*id} } + case maintenanceentry.EdgePlan: + if id := m.plan; id != nil { + return []ent.Value{*id} + } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *MaintenanceEntryMutation) RemovedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) return edges } @@ -12134,10 +12327,13 @@ func (m *MaintenanceEntryMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *MaintenanceEntryMutation) ClearedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) if m.clearedentity { edges = append(edges, maintenanceentry.EdgeEntity) } + if m.clearedplan { + edges = append(edges, maintenanceentry.EdgePlan) + } return edges } @@ -12147,6 +12343,8 @@ func (m *MaintenanceEntryMutation) EdgeCleared(name string) bool { switch name { case maintenanceentry.EdgeEntity: return m.clearedentity + case maintenanceentry.EdgePlan: + return m.clearedplan } return false } @@ -12158,6 +12356,9 @@ func (m *MaintenanceEntryMutation) ClearEdge(name string) error { case maintenanceentry.EdgeEntity: m.ClearEntity() return nil + case maintenanceentry.EdgePlan: + m.ClearPlan() + return nil } return fmt.Errorf("unknown MaintenanceEntry unique edge %s", name) } @@ -12169,10 +12370,1066 @@ func (m *MaintenanceEntryMutation) ResetEdge(name string) error { case maintenanceentry.EdgeEntity: m.ResetEntity() return nil + case maintenanceentry.EdgePlan: + m.ResetPlan() + return nil } return fmt.Errorf("unknown MaintenanceEntry edge %s", name) } +// MaintenancePlanMutation represents an operation that mutates the MaintenancePlan nodes in the graph. +type MaintenancePlanMutation struct { + config + op Op + typ string + id *uuid.UUID + created_at *time.Time + updated_at *time.Time + name *string + description *string + interval_value *int + addinterval_value *int + interval_unit *maintenanceplan.IntervalUnit + active *bool + last_completed_at *time.Time + next_due_at *time.Time + clearedFields map[string]struct{} + entity *uuid.UUID + clearedentity bool + maintenance_entries map[uuid.UUID]struct{} + removedmaintenance_entries map[uuid.UUID]struct{} + clearedmaintenance_entries bool + done bool + oldValue func(context.Context) (*MaintenancePlan, error) + predicates []predicate.MaintenancePlan +} + +var _ ent.Mutation = (*MaintenancePlanMutation)(nil) + +// maintenanceplanOption allows management of the mutation configuration using functional options. +type maintenanceplanOption func(*MaintenancePlanMutation) + +// newMaintenancePlanMutation creates new mutation for the MaintenancePlan entity. +func newMaintenancePlanMutation(c config, op Op, opts ...maintenanceplanOption) *MaintenancePlanMutation { + m := &MaintenancePlanMutation{ + config: c, + op: op, + typ: TypeMaintenancePlan, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withMaintenancePlanID sets the ID field of the mutation. +func withMaintenancePlanID(id uuid.UUID) maintenanceplanOption { + return func(m *MaintenancePlanMutation) { + var ( + err error + once sync.Once + value *MaintenancePlan + ) + m.oldValue = func(ctx context.Context) (*MaintenancePlan, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().MaintenancePlan.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withMaintenancePlan sets the old MaintenancePlan of the mutation. +func withMaintenancePlan(node *MaintenancePlan) maintenanceplanOption { + return func(m *MaintenancePlanMutation) { + m.oldValue = func(context.Context) (*MaintenancePlan, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m MaintenancePlanMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m MaintenancePlanMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of MaintenancePlan entities. +func (m *MaintenancePlanMutation) SetID(id uuid.UUID) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *MaintenancePlanMutation) ID() (id uuid.UUID, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *MaintenancePlanMutation) IDs(ctx context.Context) ([]uuid.UUID, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []uuid.UUID{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().MaintenancePlan.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *MaintenancePlanMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *MaintenancePlanMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *MaintenancePlanMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *MaintenancePlanMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *MaintenancePlanMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *MaintenancePlanMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetEntityID sets the "entity_id" field. +func (m *MaintenancePlanMutation) SetEntityID(u uuid.UUID) { + m.entity = &u +} + +// EntityID returns the value of the "entity_id" field in the mutation. +func (m *MaintenancePlanMutation) EntityID() (r uuid.UUID, exists bool) { + v := m.entity + if v == nil { + return + } + return *v, true +} + +// OldEntityID returns the old "entity_id" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldEntityID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEntityID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEntityID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEntityID: %w", err) + } + return oldValue.EntityID, nil +} + +// ResetEntityID resets all changes to the "entity_id" field. +func (m *MaintenancePlanMutation) ResetEntityID() { + m.entity = nil +} + +// SetName sets the "name" field. +func (m *MaintenancePlanMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *MaintenancePlanMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *MaintenancePlanMutation) ResetName() { + m.name = nil +} + +// SetDescription sets the "description" field. +func (m *MaintenancePlanMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *MaintenancePlanMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *MaintenancePlanMutation) ClearDescription() { + m.description = nil + m.clearedFields[maintenanceplan.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *MaintenancePlanMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[maintenanceplan.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *MaintenancePlanMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, maintenanceplan.FieldDescription) +} + +// SetIntervalValue sets the "interval_value" field. +func (m *MaintenancePlanMutation) SetIntervalValue(i int) { + m.interval_value = &i + m.addinterval_value = nil +} + +// IntervalValue returns the value of the "interval_value" field in the mutation. +func (m *MaintenancePlanMutation) IntervalValue() (r int, exists bool) { + v := m.interval_value + if v == nil { + return + } + return *v, true +} + +// OldIntervalValue returns the old "interval_value" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldIntervalValue(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldIntervalValue is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldIntervalValue requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldIntervalValue: %w", err) + } + return oldValue.IntervalValue, nil +} + +// AddIntervalValue adds i to the "interval_value" field. +func (m *MaintenancePlanMutation) AddIntervalValue(i int) { + if m.addinterval_value != nil { + *m.addinterval_value += i + } else { + m.addinterval_value = &i + } +} + +// AddedIntervalValue returns the value that was added to the "interval_value" field in this mutation. +func (m *MaintenancePlanMutation) AddedIntervalValue() (r int, exists bool) { + v := m.addinterval_value + if v == nil { + return + } + return *v, true +} + +// ResetIntervalValue resets all changes to the "interval_value" field. +func (m *MaintenancePlanMutation) ResetIntervalValue() { + m.interval_value = nil + m.addinterval_value = nil +} + +// SetIntervalUnit sets the "interval_unit" field. +func (m *MaintenancePlanMutation) SetIntervalUnit(mu maintenanceplan.IntervalUnit) { + m.interval_unit = &mu +} + +// IntervalUnit returns the value of the "interval_unit" field in the mutation. +func (m *MaintenancePlanMutation) IntervalUnit() (r maintenanceplan.IntervalUnit, exists bool) { + v := m.interval_unit + if v == nil { + return + } + return *v, true +} + +// OldIntervalUnit returns the old "interval_unit" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldIntervalUnit(ctx context.Context) (v maintenanceplan.IntervalUnit, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldIntervalUnit is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldIntervalUnit requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldIntervalUnit: %w", err) + } + return oldValue.IntervalUnit, nil +} + +// ResetIntervalUnit resets all changes to the "interval_unit" field. +func (m *MaintenancePlanMutation) ResetIntervalUnit() { + m.interval_unit = nil +} + +// SetActive sets the "active" field. +func (m *MaintenancePlanMutation) SetActive(b bool) { + m.active = &b +} + +// Active returns the value of the "active" field in the mutation. +func (m *MaintenancePlanMutation) Active() (r bool, exists bool) { + v := m.active + if v == nil { + return + } + return *v, true +} + +// OldActive returns the old "active" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldActive(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldActive is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldActive requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldActive: %w", err) + } + return oldValue.Active, nil +} + +// ResetActive resets all changes to the "active" field. +func (m *MaintenancePlanMutation) ResetActive() { + m.active = nil +} + +// SetLastCompletedAt sets the "last_completed_at" field. +func (m *MaintenancePlanMutation) SetLastCompletedAt(t time.Time) { + m.last_completed_at = &t +} + +// LastCompletedAt returns the value of the "last_completed_at" field in the mutation. +func (m *MaintenancePlanMutation) LastCompletedAt() (r time.Time, exists bool) { + v := m.last_completed_at + if v == nil { + return + } + return *v, true +} + +// OldLastCompletedAt returns the old "last_completed_at" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldLastCompletedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLastCompletedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLastCompletedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLastCompletedAt: %w", err) + } + return oldValue.LastCompletedAt, nil +} + +// ClearLastCompletedAt clears the value of the "last_completed_at" field. +func (m *MaintenancePlanMutation) ClearLastCompletedAt() { + m.last_completed_at = nil + m.clearedFields[maintenanceplan.FieldLastCompletedAt] = struct{}{} +} + +// LastCompletedAtCleared returns if the "last_completed_at" field was cleared in this mutation. +func (m *MaintenancePlanMutation) LastCompletedAtCleared() bool { + _, ok := m.clearedFields[maintenanceplan.FieldLastCompletedAt] + return ok +} + +// ResetLastCompletedAt resets all changes to the "last_completed_at" field. +func (m *MaintenancePlanMutation) ResetLastCompletedAt() { + m.last_completed_at = nil + delete(m.clearedFields, maintenanceplan.FieldLastCompletedAt) +} + +// SetNextDueAt sets the "next_due_at" field. +func (m *MaintenancePlanMutation) SetNextDueAt(t time.Time) { + m.next_due_at = &t +} + +// NextDueAt returns the value of the "next_due_at" field in the mutation. +func (m *MaintenancePlanMutation) NextDueAt() (r time.Time, exists bool) { + v := m.next_due_at + if v == nil { + return + } + return *v, true +} + +// OldNextDueAt returns the old "next_due_at" field's value of the MaintenancePlan entity. +// If the MaintenancePlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *MaintenancePlanMutation) OldNextDueAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldNextDueAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldNextDueAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldNextDueAt: %w", err) + } + return oldValue.NextDueAt, nil +} + +// ClearNextDueAt clears the value of the "next_due_at" field. +func (m *MaintenancePlanMutation) ClearNextDueAt() { + m.next_due_at = nil + m.clearedFields[maintenanceplan.FieldNextDueAt] = struct{}{} +} + +// NextDueAtCleared returns if the "next_due_at" field was cleared in this mutation. +func (m *MaintenancePlanMutation) NextDueAtCleared() bool { + _, ok := m.clearedFields[maintenanceplan.FieldNextDueAt] + return ok +} + +// ResetNextDueAt resets all changes to the "next_due_at" field. +func (m *MaintenancePlanMutation) ResetNextDueAt() { + m.next_due_at = nil + delete(m.clearedFields, maintenanceplan.FieldNextDueAt) +} + +// ClearEntity clears the "entity" edge to the Entity entity. +func (m *MaintenancePlanMutation) ClearEntity() { + m.clearedentity = true + m.clearedFields[maintenanceplan.FieldEntityID] = struct{}{} +} + +// EntityCleared reports if the "entity" edge to the Entity entity was cleared. +func (m *MaintenancePlanMutation) EntityCleared() bool { + return m.clearedentity +} + +// EntityIDs returns the "entity" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// EntityID instead. It exists only for internal usage by the builders. +func (m *MaintenancePlanMutation) EntityIDs() (ids []uuid.UUID) { + if id := m.entity; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetEntity resets all changes to the "entity" edge. +func (m *MaintenancePlanMutation) ResetEntity() { + m.entity = nil + m.clearedentity = false +} + +// AddMaintenanceEntryIDs adds the "maintenance_entries" edge to the MaintenanceEntry entity by ids. +func (m *MaintenancePlanMutation) AddMaintenanceEntryIDs(ids ...uuid.UUID) { + if m.maintenance_entries == nil { + m.maintenance_entries = make(map[uuid.UUID]struct{}) + } + for i := range ids { + m.maintenance_entries[ids[i]] = struct{}{} + } +} + +// ClearMaintenanceEntries clears the "maintenance_entries" edge to the MaintenanceEntry entity. +func (m *MaintenancePlanMutation) ClearMaintenanceEntries() { + m.clearedmaintenance_entries = true +} + +// MaintenanceEntriesCleared reports if the "maintenance_entries" edge to the MaintenanceEntry entity was cleared. +func (m *MaintenancePlanMutation) MaintenanceEntriesCleared() bool { + return m.clearedmaintenance_entries +} + +// RemoveMaintenanceEntryIDs removes the "maintenance_entries" edge to the MaintenanceEntry entity by IDs. +func (m *MaintenancePlanMutation) RemoveMaintenanceEntryIDs(ids ...uuid.UUID) { + if m.removedmaintenance_entries == nil { + m.removedmaintenance_entries = make(map[uuid.UUID]struct{}) + } + for i := range ids { + delete(m.maintenance_entries, ids[i]) + m.removedmaintenance_entries[ids[i]] = struct{}{} + } +} + +// RemovedMaintenanceEntries returns the removed IDs of the "maintenance_entries" edge to the MaintenanceEntry entity. +func (m *MaintenancePlanMutation) RemovedMaintenanceEntriesIDs() (ids []uuid.UUID) { + for id := range m.removedmaintenance_entries { + ids = append(ids, id) + } + return +} + +// MaintenanceEntriesIDs returns the "maintenance_entries" edge IDs in the mutation. +func (m *MaintenancePlanMutation) MaintenanceEntriesIDs() (ids []uuid.UUID) { + for id := range m.maintenance_entries { + ids = append(ids, id) + } + return +} + +// ResetMaintenanceEntries resets all changes to the "maintenance_entries" edge. +func (m *MaintenancePlanMutation) ResetMaintenanceEntries() { + m.maintenance_entries = nil + m.clearedmaintenance_entries = false + m.removedmaintenance_entries = nil +} + +// Where appends a list predicates to the MaintenancePlanMutation builder. +func (m *MaintenancePlanMutation) Where(ps ...predicate.MaintenancePlan) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the MaintenancePlanMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *MaintenancePlanMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.MaintenancePlan, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *MaintenancePlanMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *MaintenancePlanMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (MaintenancePlan). +func (m *MaintenancePlanMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *MaintenancePlanMutation) Fields() []string { + fields := make([]string, 0, 10) + if m.created_at != nil { + fields = append(fields, maintenanceplan.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, maintenanceplan.FieldUpdatedAt) + } + if m.entity != nil { + fields = append(fields, maintenanceplan.FieldEntityID) + } + if m.name != nil { + fields = append(fields, maintenanceplan.FieldName) + } + if m.description != nil { + fields = append(fields, maintenanceplan.FieldDescription) + } + if m.interval_value != nil { + fields = append(fields, maintenanceplan.FieldIntervalValue) + } + if m.interval_unit != nil { + fields = append(fields, maintenanceplan.FieldIntervalUnit) + } + if m.active != nil { + fields = append(fields, maintenanceplan.FieldActive) + } + if m.last_completed_at != nil { + fields = append(fields, maintenanceplan.FieldLastCompletedAt) + } + if m.next_due_at != nil { + fields = append(fields, maintenanceplan.FieldNextDueAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *MaintenancePlanMutation) Field(name string) (ent.Value, bool) { + switch name { + case maintenanceplan.FieldCreatedAt: + return m.CreatedAt() + case maintenanceplan.FieldUpdatedAt: + return m.UpdatedAt() + case maintenanceplan.FieldEntityID: + return m.EntityID() + case maintenanceplan.FieldName: + return m.Name() + case maintenanceplan.FieldDescription: + return m.Description() + case maintenanceplan.FieldIntervalValue: + return m.IntervalValue() + case maintenanceplan.FieldIntervalUnit: + return m.IntervalUnit() + case maintenanceplan.FieldActive: + return m.Active() + case maintenanceplan.FieldLastCompletedAt: + return m.LastCompletedAt() + case maintenanceplan.FieldNextDueAt: + return m.NextDueAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *MaintenancePlanMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case maintenanceplan.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case maintenanceplan.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case maintenanceplan.FieldEntityID: + return m.OldEntityID(ctx) + case maintenanceplan.FieldName: + return m.OldName(ctx) + case maintenanceplan.FieldDescription: + return m.OldDescription(ctx) + case maintenanceplan.FieldIntervalValue: + return m.OldIntervalValue(ctx) + case maintenanceplan.FieldIntervalUnit: + return m.OldIntervalUnit(ctx) + case maintenanceplan.FieldActive: + return m.OldActive(ctx) + case maintenanceplan.FieldLastCompletedAt: + return m.OldLastCompletedAt(ctx) + case maintenanceplan.FieldNextDueAt: + return m.OldNextDueAt(ctx) + } + return nil, fmt.Errorf("unknown MaintenancePlan field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *MaintenancePlanMutation) SetField(name string, value ent.Value) error { + switch name { + case maintenanceplan.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case maintenanceplan.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + case maintenanceplan.FieldEntityID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEntityID(v) + return nil + case maintenanceplan.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case maintenanceplan.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil + case maintenanceplan.FieldIntervalValue: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetIntervalValue(v) + return nil + case maintenanceplan.FieldIntervalUnit: + v, ok := value.(maintenanceplan.IntervalUnit) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetIntervalUnit(v) + return nil + case maintenanceplan.FieldActive: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetActive(v) + return nil + case maintenanceplan.FieldLastCompletedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLastCompletedAt(v) + return nil + case maintenanceplan.FieldNextDueAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetNextDueAt(v) + return nil + } + return fmt.Errorf("unknown MaintenancePlan field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *MaintenancePlanMutation) AddedFields() []string { + var fields []string + if m.addinterval_value != nil { + fields = append(fields, maintenanceplan.FieldIntervalValue) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *MaintenancePlanMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case maintenanceplan.FieldIntervalValue: + return m.AddedIntervalValue() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *MaintenancePlanMutation) AddField(name string, value ent.Value) error { + switch name { + case maintenanceplan.FieldIntervalValue: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddIntervalValue(v) + return nil + } + return fmt.Errorf("unknown MaintenancePlan numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *MaintenancePlanMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(maintenanceplan.FieldDescription) { + fields = append(fields, maintenanceplan.FieldDescription) + } + if m.FieldCleared(maintenanceplan.FieldLastCompletedAt) { + fields = append(fields, maintenanceplan.FieldLastCompletedAt) + } + if m.FieldCleared(maintenanceplan.FieldNextDueAt) { + fields = append(fields, maintenanceplan.FieldNextDueAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *MaintenancePlanMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *MaintenancePlanMutation) ClearField(name string) error { + switch name { + case maintenanceplan.FieldDescription: + m.ClearDescription() + return nil + case maintenanceplan.FieldLastCompletedAt: + m.ClearLastCompletedAt() + return nil + case maintenanceplan.FieldNextDueAt: + m.ClearNextDueAt() + return nil + } + return fmt.Errorf("unknown MaintenancePlan nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *MaintenancePlanMutation) ResetField(name string) error { + switch name { + case maintenanceplan.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case maintenanceplan.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case maintenanceplan.FieldEntityID: + m.ResetEntityID() + return nil + case maintenanceplan.FieldName: + m.ResetName() + return nil + case maintenanceplan.FieldDescription: + m.ResetDescription() + return nil + case maintenanceplan.FieldIntervalValue: + m.ResetIntervalValue() + return nil + case maintenanceplan.FieldIntervalUnit: + m.ResetIntervalUnit() + return nil + case maintenanceplan.FieldActive: + m.ResetActive() + return nil + case maintenanceplan.FieldLastCompletedAt: + m.ResetLastCompletedAt() + return nil + case maintenanceplan.FieldNextDueAt: + m.ResetNextDueAt() + return nil + } + return fmt.Errorf("unknown MaintenancePlan field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *MaintenancePlanMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.entity != nil { + edges = append(edges, maintenanceplan.EdgeEntity) + } + if m.maintenance_entries != nil { + edges = append(edges, maintenanceplan.EdgeMaintenanceEntries) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *MaintenancePlanMutation) AddedIDs(name string) []ent.Value { + switch name { + case maintenanceplan.EdgeEntity: + if id := m.entity; id != nil { + return []ent.Value{*id} + } + case maintenanceplan.EdgeMaintenanceEntries: + ids := make([]ent.Value, 0, len(m.maintenance_entries)) + for id := range m.maintenance_entries { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *MaintenancePlanMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + if m.removedmaintenance_entries != nil { + edges = append(edges, maintenanceplan.EdgeMaintenanceEntries) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *MaintenancePlanMutation) RemovedIDs(name string) []ent.Value { + switch name { + case maintenanceplan.EdgeMaintenanceEntries: + ids := make([]ent.Value, 0, len(m.removedmaintenance_entries)) + for id := range m.removedmaintenance_entries { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *MaintenancePlanMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.clearedentity { + edges = append(edges, maintenanceplan.EdgeEntity) + } + if m.clearedmaintenance_entries { + edges = append(edges, maintenanceplan.EdgeMaintenanceEntries) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *MaintenancePlanMutation) EdgeCleared(name string) bool { + switch name { + case maintenanceplan.EdgeEntity: + return m.clearedentity + case maintenanceplan.EdgeMaintenanceEntries: + return m.clearedmaintenance_entries + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *MaintenancePlanMutation) ClearEdge(name string) error { + switch name { + case maintenanceplan.EdgeEntity: + m.ClearEntity() + return nil + } + return fmt.Errorf("unknown MaintenancePlan unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *MaintenancePlanMutation) ResetEdge(name string) error { + switch name { + case maintenanceplan.EdgeEntity: + m.ResetEntity() + return nil + case maintenanceplan.EdgeMaintenanceEntries: + m.ResetMaintenanceEntries() + return nil + } + return fmt.Errorf("unknown MaintenancePlan edge %s", name) +} + // NotifierMutation represents an operation that mutates the Notifier nodes in the graph. type NotifierMutation struct { config diff --git a/backend/internal/data/ent/predicate/predicate.go b/backend/internal/data/ent/predicate/predicate.go index 5801da30d..f2af221b1 100644 --- a/backend/internal/data/ent/predicate/predicate.go +++ b/backend/internal/data/ent/predicate/predicate.go @@ -42,6 +42,9 @@ type GroupInvitationToken func(*sql.Selector) // MaintenanceEntry is the predicate function for maintenanceentry builders. type MaintenanceEntry func(*sql.Selector) +// MaintenancePlan is the predicate function for maintenanceplan builders. +type MaintenancePlan func(*sql.Selector) + // Notifier is the predicate function for notifier builders. type Notifier func(*sql.Selector) diff --git a/backend/internal/data/ent/runtime.go b/backend/internal/data/ent/runtime.go index 416198439..aacddfdf5 100644 --- a/backend/internal/data/ent/runtime.go +++ b/backend/internal/data/ent/runtime.go @@ -17,6 +17,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/groupinvitationtoken" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/notifier" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/passwordresettokens" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/schema" @@ -541,7 +542,7 @@ func init() { // maintenanceentry.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. maintenanceentry.UpdateDefaultUpdatedAt = maintenanceentryDescUpdatedAt.UpdateDefault.(func() time.Time) // maintenanceentryDescName is the schema descriptor for name field. - maintenanceentryDescName := maintenanceentryFields[3].Descriptor() + maintenanceentryDescName := maintenanceentryFields[4].Descriptor() // maintenanceentry.NameValidator is a validator for the "name" field. It is called by the builders before save. maintenanceentry.NameValidator = func() func(string) error { validators := maintenanceentryDescName.Validators @@ -559,17 +560,66 @@ func init() { } }() // maintenanceentryDescDescription is the schema descriptor for description field. - maintenanceentryDescDescription := maintenanceentryFields[4].Descriptor() + maintenanceentryDescDescription := maintenanceentryFields[5].Descriptor() // maintenanceentry.DescriptionValidator is a validator for the "description" field. It is called by the builders before save. maintenanceentry.DescriptionValidator = maintenanceentryDescDescription.Validators[0].(func(string) error) // maintenanceentryDescCost is the schema descriptor for cost field. - maintenanceentryDescCost := maintenanceentryFields[5].Descriptor() + maintenanceentryDescCost := maintenanceentryFields[6].Descriptor() // maintenanceentry.DefaultCost holds the default value on creation for the cost field. maintenanceentry.DefaultCost = maintenanceentryDescCost.Default.(float64) // maintenanceentryDescID is the schema descriptor for id field. maintenanceentryDescID := maintenanceentryMixinFields0[0].Descriptor() // maintenanceentry.DefaultID holds the default value on creation for the id field. maintenanceentry.DefaultID = maintenanceentryDescID.Default.(func() uuid.UUID) + maintenanceplanMixin := schema.MaintenancePlan{}.Mixin() + maintenanceplanMixinFields0 := maintenanceplanMixin[0].Fields() + _ = maintenanceplanMixinFields0 + maintenanceplanFields := schema.MaintenancePlan{}.Fields() + _ = maintenanceplanFields + // maintenanceplanDescCreatedAt is the schema descriptor for created_at field. + maintenanceplanDescCreatedAt := maintenanceplanMixinFields0[1].Descriptor() + // maintenanceplan.DefaultCreatedAt holds the default value on creation for the created_at field. + maintenanceplan.DefaultCreatedAt = maintenanceplanDescCreatedAt.Default.(func() time.Time) + // maintenanceplanDescUpdatedAt is the schema descriptor for updated_at field. + maintenanceplanDescUpdatedAt := maintenanceplanMixinFields0[2].Descriptor() + // maintenanceplan.DefaultUpdatedAt holds the default value on creation for the updated_at field. + maintenanceplan.DefaultUpdatedAt = maintenanceplanDescUpdatedAt.Default.(func() time.Time) + // maintenanceplan.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + maintenanceplan.UpdateDefaultUpdatedAt = maintenanceplanDescUpdatedAt.UpdateDefault.(func() time.Time) + // maintenanceplanDescName is the schema descriptor for name field. + maintenanceplanDescName := maintenanceplanFields[1].Descriptor() + // maintenanceplan.NameValidator is a validator for the "name" field. It is called by the builders before save. + maintenanceplan.NameValidator = func() func(string) error { + validators := maintenanceplanDescName.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(name string) error { + for _, fn := range fns { + if err := fn(name); err != nil { + return err + } + } + return nil + } + }() + // maintenanceplanDescDescription is the schema descriptor for description field. + maintenanceplanDescDescription := maintenanceplanFields[2].Descriptor() + // maintenanceplan.DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + maintenanceplan.DescriptionValidator = maintenanceplanDescDescription.Validators[0].(func(string) error) + // maintenanceplanDescIntervalValue is the schema descriptor for interval_value field. + maintenanceplanDescIntervalValue := maintenanceplanFields[3].Descriptor() + // maintenanceplan.IntervalValueValidator is a validator for the "interval_value" field. It is called by the builders before save. + maintenanceplan.IntervalValueValidator = maintenanceplanDescIntervalValue.Validators[0].(func(int) error) + // maintenanceplanDescActive is the schema descriptor for active field. + maintenanceplanDescActive := maintenanceplanFields[5].Descriptor() + // maintenanceplan.DefaultActive holds the default value on creation for the active field. + maintenanceplan.DefaultActive = maintenanceplanDescActive.Default.(bool) + // maintenanceplanDescID is the schema descriptor for id field. + maintenanceplanDescID := maintenanceplanMixinFields0[0].Descriptor() + // maintenanceplan.DefaultID holds the default value on creation for the id field. + maintenanceplan.DefaultID = maintenanceplanDescID.Default.(func() uuid.UUID) notifierMixin := schema.Notifier{}.Mixin() notifierMixinFields0 := notifierMixin[0].Fields() _ = notifierMixinFields0 diff --git a/backend/internal/data/ent/schema/entity.go b/backend/internal/data/ent/schema/entity.go index c5cf5c874..59e17b658 100644 --- a/backend/internal/data/ent/schema/entity.go +++ b/backend/internal/data/ent/schema/entity.go @@ -119,6 +119,7 @@ func (Entity) Edges() []ent.Edge { Required(), owned("fields", EntityField.Type), owned("maintenance_entries", MaintenanceEntry.Type), + owned("maintenance_plans", MaintenancePlan.Type), owned("attachments", Attachment.Type), } } diff --git a/backend/internal/data/ent/schema/maintenance_entry.go b/backend/internal/data/ent/schema/maintenance_entry.go index 00fa94e47..714a9c8fa 100644 --- a/backend/internal/data/ent/schema/maintenance_entry.go +++ b/backend/internal/data/ent/schema/maintenance_entry.go @@ -21,6 +21,9 @@ func (MaintenanceEntry) Mixin() []ent.Mixin { func (MaintenanceEntry) Fields() []ent.Field { return []ent.Field{ field.UUID("entity_id", uuid.UUID{}), + field.UUID("plan_id", uuid.UUID{}). + Optional(). + Nillable(), field.Time("date"). Optional(), field.Time("scheduled_date"). @@ -44,5 +47,9 @@ func (MaintenanceEntry) Edges() []ent.Edge { Ref("maintenance_entries"). Required(). Unique(), + edge.From("plan", MaintenancePlan.Type). + Field("plan_id"). + Ref("maintenance_entries"). + Unique(), } } diff --git a/backend/internal/data/ent/schema/maintenance_plan.go b/backend/internal/data/ent/schema/maintenance_plan.go new file mode 100644 index 000000000..1ae82fd55 --- /dev/null +++ b/backend/internal/data/ent/schema/maintenance_plan.go @@ -0,0 +1,74 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/schema/mixins" +) + +type MaintenanceIntervalUnit string + +const ( + MaintenanceIntervalUnitHour MaintenanceIntervalUnit = "hour" + MaintenanceIntervalUnitDay MaintenanceIntervalUnit = "day" + MaintenanceIntervalUnitWeek MaintenanceIntervalUnit = "week" + MaintenanceIntervalUnitMonth MaintenanceIntervalUnit = "month" + MaintenanceIntervalUnitYear MaintenanceIntervalUnit = "year" +) + +type MaintenancePlan struct { + ent.Schema +} + +func (MaintenancePlan) Mixin() []ent.Mixin { + return []ent.Mixin{ + mixins.BaseMixin{}, + } +} + +func (MaintenancePlan) Fields() []ent.Field { + return []ent.Field{ + field.UUID("entity_id", uuid.UUID{}), + field.String("name"). + MaxLen(255). + NotEmpty(), + field.String("description"). + MaxLen(2500). + Optional(), + field.Int("interval_value"). + Positive(), + field.Enum("interval_unit"). + Values( + string(MaintenanceIntervalUnitHour), + string(MaintenanceIntervalUnitDay), + string(MaintenanceIntervalUnitWeek), + string(MaintenanceIntervalUnitMonth), + string(MaintenanceIntervalUnitYear), + ), + field.Bool("active"). + Default(true), + field.Time("last_completed_at"). + Optional(). + Nillable(), + field.Time("next_due_at"). + Optional(). + Nillable(), + } +} + +func (MaintenancePlan) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("entity", Entity.Type). + Field("entity_id"). + Ref("maintenance_plans"). + Required(). + Unique(), + edge.To("maintenance_entries", MaintenanceEntry.Type). + Annotations(entsql.Annotation{ + OnDelete: entsql.SetNull, + }), + } +} diff --git a/backend/internal/data/ent/tx.go b/backend/internal/data/ent/tx.go index 9128dffac..9ecdd7b30 100644 --- a/backend/internal/data/ent/tx.go +++ b/backend/internal/data/ent/tx.go @@ -36,6 +36,8 @@ type Tx struct { GroupInvitationToken *GroupInvitationTokenClient // MaintenanceEntry is the client for interacting with the MaintenanceEntry builders. MaintenanceEntry *MaintenanceEntryClient + // MaintenancePlan is the client for interacting with the MaintenancePlan builders. + MaintenancePlan *MaintenancePlanClient // Notifier is the client for interacting with the Notifier builders. Notifier *NotifierClient // PasswordResetTokens is the client for interacting with the PasswordResetTokens builders. @@ -191,6 +193,7 @@ func (tx *Tx) init() { tx.Group = NewGroupClient(tx.config) tx.GroupInvitationToken = NewGroupInvitationTokenClient(tx.config) tx.MaintenanceEntry = NewMaintenanceEntryClient(tx.config) + tx.MaintenancePlan = NewMaintenancePlanClient(tx.config) tx.Notifier = NewNotifierClient(tx.config) tx.PasswordResetTokens = NewPasswordResetTokensClient(tx.config) tx.Tag = NewTagClient(tx.config) diff --git a/backend/internal/data/migrations/postgres/20260424120001_add_maintenance_plans.sql b/backend/internal/data/migrations/postgres/20260424120001_add_maintenance_plans.sql new file mode 100644 index 000000000..666b1aa32 --- /dev/null +++ b/backend/internal/data/migrations/postgres/20260424120001_add_maintenance_plans.sql @@ -0,0 +1,34 @@ +-- +goose Up +CREATE TABLE maintenance_plans ( + id uuid NOT NULL PRIMARY KEY, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + entity_id uuid NOT NULL, + name text NOT NULL, + description text, + interval_value bigint NOT NULL, + interval_unit text NOT NULL, + active boolean DEFAULT true NOT NULL, + last_completed_at timestamp with time zone, + next_due_at timestamp with time zone, + CONSTRAINT maintenance_plans_entities_maintenance_plans + FOREIGN KEY (entity_id) REFERENCES entities (id) ON DELETE CASCADE +); + +CREATE INDEX idx_maintenance_plans_entity_id ON maintenance_plans (entity_id); + +ALTER TABLE maintenance_entries + ADD COLUMN plan_id uuid; + +ALTER TABLE maintenance_entries + ADD CONSTRAINT maintenance_entries_plan_id_fkey + FOREIGN KEY (plan_id) REFERENCES maintenance_plans (id) ON DELETE SET NULL; + +CREATE INDEX idx_maintenance_entries_plan_id ON maintenance_entries (plan_id); + +-- +goose Down +DROP INDEX IF EXISTS idx_maintenance_entries_plan_id; +ALTER TABLE maintenance_entries DROP CONSTRAINT IF EXISTS maintenance_entries_plan_id_fkey; +ALTER TABLE maintenance_entries DROP COLUMN IF EXISTS plan_id; +DROP INDEX IF EXISTS idx_maintenance_plans_entity_id; +DROP TABLE IF EXISTS maintenance_plans; diff --git a/backend/internal/data/migrations/sqlite3/20260424120000_add_maintenance_plans.sql b/backend/internal/data/migrations/sqlite3/20260424120000_add_maintenance_plans.sql new file mode 100644 index 000000000..f8a90412a --- /dev/null +++ b/backend/internal/data/migrations/sqlite3/20260424120000_add_maintenance_plans.sql @@ -0,0 +1,78 @@ +-- +goose Up +CREATE TABLE maintenance_plans ( + id uuid NOT NULL PRIMARY KEY, + created_at datetime NOT NULL, + updated_at datetime NOT NULL, + entity_id uuid NOT NULL, + name text NOT NULL, + description text, + interval_value integer NOT NULL, + interval_unit text NOT NULL, + active boolean DEFAULT true NOT NULL, + last_completed_at datetime, + next_due_at datetime, + CONSTRAINT maintenance_plans_entities_maintenance_plans + FOREIGN KEY (entity_id) REFERENCES entities (id) ON DELETE CASCADE +); + +CREATE INDEX idx_maintenance_plans_entity_id ON maintenance_plans (entity_id); + +CREATE TABLE maintenance_entries_new ( + id uuid not null primary key, + created_at datetime not null, + updated_at datetime not null, + date datetime, + scheduled_date datetime, + name text not null, + description text, + cost real default 0 not null, + entity_id uuid not null + constraint maintenance_entries_entities_maintenance_entries + references entities (id) on delete cascade, + plan_id uuid + constraint maintenance_entries_plan_id_fkey + references maintenance_plans (id) on delete set null +); + +INSERT INTO maintenance_entries_new ( + id, created_at, updated_at, date, scheduled_date, name, description, cost, entity_id, plan_id +) +SELECT + id, created_at, updated_at, date, scheduled_date, name, description, cost, entity_id, NULL +FROM maintenance_entries; + +DROP TABLE maintenance_entries; + +ALTER TABLE maintenance_entries_new RENAME TO maintenance_entries; + +CREATE INDEX idx_maintenance_entries_plan_id ON maintenance_entries (plan_id); + +-- +goose Down +DROP INDEX IF EXISTS idx_maintenance_entries_plan_id; + +CREATE TABLE maintenance_entries_old ( + id uuid not null primary key, + created_at datetime not null, + updated_at datetime not null, + date datetime, + scheduled_date datetime, + name text not null, + description text, + cost real default 0 not null, + entity_id uuid not null + constraint maintenance_entries_entities_maintenance_entries_old + references entities (id) on delete cascade +); + +INSERT INTO maintenance_entries_old ( + id, created_at, updated_at, date, scheduled_date, name, description, cost, entity_id +) +SELECT id, created_at, updated_at, date, scheduled_date, name, description, cost, entity_id +FROM maintenance_entries; + +DROP TABLE maintenance_entries; + +ALTER TABLE maintenance_entries_old RENAME TO maintenance_entries; + +DROP INDEX IF EXISTS idx_maintenance_plans_entity_id; +DROP TABLE IF EXISTS maintenance_plans; diff --git a/backend/internal/data/repo/repo_maintenance.go b/backend/internal/data/repo/repo_maintenance.go index 39f82dd68..53184e931 100644 --- a/backend/internal/data/repo/repo_maintenance.go +++ b/backend/internal/data/repo/repo_maintenance.go @@ -36,6 +36,7 @@ type MaintenanceFilterStatus string const ( MaintenanceFilterStatusScheduled MaintenanceFilterStatus = "scheduled" + MaintenanceFilterStatusOverdue MaintenanceFilterStatus = "overdue" MaintenanceFilterStatusCompleted MaintenanceFilterStatus = "completed" MaintenanceFilterStatusBoth MaintenanceFilterStatus = "both" ) @@ -57,6 +58,14 @@ func (r *MaintenanceEntryRepository) GetAllMaintenance(ctx context.Context, grou maintenanceentry.DateIsNil(), maintenanceentry.DateEQ(time.Time{}), )) + case MaintenanceFilterStatusOverdue: + query = query.Where( + maintenanceentry.ScheduledDateLT(time.Now()), + maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), + ), + ) case MaintenanceFilterStatusCompleted: query = query.Where( maintenanceentry.Not(maintenanceentry.Or( diff --git a/backend/internal/data/repo/repo_maintenance_entry.go b/backend/internal/data/repo/repo_maintenance_entry.go index 930d9ba2c..6ec3855c0 100644 --- a/backend/internal/data/repo/repo_maintenance_entry.go +++ b/backend/internal/data/repo/repo_maintenance_entry.go @@ -24,6 +24,7 @@ type MaintenanceEntryRepository struct { type MaintenanceEntryCreate struct { CompletedDate types.Date `json:"completedDate"` ScheduledDate types.Date `json:"scheduledDate"` + PlanID uuid.UUID `json:"planID"` Name string `json:"name" validate:"required"` Description string `json:"description"` Cost float64 `json:"cost,string"` @@ -39,6 +40,7 @@ func (mc MaintenanceEntryCreate) Validate() error { type MaintenanceEntryUpdate struct { CompletedDate types.Date `json:"completedDate"` ScheduledDate types.Date `json:"scheduledDate"` + PlanID uuid.UUID `json:"planID"` Name string `json:"name"` Description string `json:"description"` Cost float64 `json:"cost,string"` @@ -56,6 +58,8 @@ type ( ID uuid.UUID `json:"id"` CompletedDate types.Date `json:"completedDate"` ScheduledDate types.Date `json:"scheduledDate"` + PlanID uuid.UUID `json:"planID,omitempty"` + IsOverdue bool `json:"isOverdue"` Name string `json:"name"` Description string `json:"description"` Cost float64 `json:"cost,string"` @@ -68,10 +72,16 @@ var ( ) func mapMaintenanceEntry(entry *ent.MaintenanceEntry) MaintenanceEntry { + planID := uuid.Nil + if entry.PlanID != nil { + planID = *entry.PlanID + } return MaintenanceEntry{ ID: entry.ID, CompletedDate: types.Date(entry.Date), ScheduledDate: types.Date(entry.ScheduledDate), + PlanID: planID, + IsOverdue: isEntryOverdue(entry.Date, entry.ScheduledDate), Name: entry.Name, Description: entry.Description, Cost: entry.Cost, @@ -122,29 +132,76 @@ func (r *MaintenanceEntryRepository) Create(ctx context.Context, gid, itemID uui SetDescription(input.Description). SetCost(input.Cost). Save(ctx) + if err != nil { + return mapMaintenanceEntryErr(item, err) + } + + if input.PlanID != uuid.Nil { + item, err = r.db.MaintenanceEntry.UpdateOneID(item.ID). + SetPlanID(input.PlanID). + Save(ctx) + } return mapMaintenanceEntryErr(item, err) } func (r *MaintenanceEntryRepository) Update(ctx context.Context, gid uuid.UUID, id uuid.UUID, input MaintenanceEntryUpdate) (MaintenanceEntry, error) { - owned, err := r.db.MaintenanceEntry.Query().Where( + current, err := r.db.MaintenanceEntry.Query().Where( maintenanceentry.ID(id), maintenanceentry.HasEntityWith(entity.HasGroupWith(group.ID(gid))), - ).Exist(ctx) + ).Only(ctx) if err != nil { return MaintenanceEntry{}, err } - if !owned { - return MaintenanceEntry{}, &ent.NotFoundError{} + + completedDate := input.CompletedDate.Time() + if completedDate.IsZero() { + completedDate = current.Date } - item, err := r.db.MaintenanceEntry.UpdateOneID(id). - SetDate(input.CompletedDate.Time()). - SetScheduledDate(input.ScheduledDate.Time()). - SetName(input.Name). - SetDescription(input.Description). - SetCost(input.Cost). - Save(ctx) + scheduledDate := input.ScheduledDate.Time() + if scheduledDate.IsZero() { + scheduledDate = current.ScheduledDate + } + + name := input.Name + if name == "" { + name = current.Name + } + + description := input.Description + if description == "" { + description = current.Description + } + + cost := input.Cost + if input.Cost == 0 && current.Cost != 0 { + cost = current.Cost + } + + updater := r.db.MaintenanceEntry.UpdateOneID(id). + SetDate(completedDate). + SetScheduledDate(scheduledDate). + SetName(name). + SetDescription(description). + SetCost(cost) + + if input.PlanID != uuid.Nil { + updater = updater.SetPlanID(input.PlanID) + } else { + updater = updater.ClearPlanID() + } + + item, err := updater.Save(ctx) + if err != nil { + return mapMaintenanceEntryErr(item, err) + } + + if current.Date.IsZero() && !completedDate.IsZero() && item.PlanID != nil && *item.PlanID != uuid.Nil { + if _, err = r.rollPlanFromCompletion(ctx, *item.PlanID, completedDate, item.EntityID); err != nil { + return MaintenanceEntry{}, err + } + } return mapMaintenanceEntryErr(item, err) } @@ -178,6 +235,17 @@ func (r *MaintenanceEntryRepository) GetMaintenanceByItemID(ctx context.Context, query = query.Order( maintenanceentry.ByDate(sql.OrderDesc()), ) + case MaintenanceFilterStatusOverdue: + query = query.Where( + maintenanceentry.ScheduledDateLT(time.Now()), + maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), + ), + ) + query = query.Order( + maintenanceentry.ByScheduledDate(sql.OrderAsc()), + ) default: // Sort entries by default by scheduled and maintenance date in descending order query = query.Order( @@ -194,6 +262,18 @@ func (r *MaintenanceEntryRepository) GetMaintenanceByItemID(ctx context.Context, return mapEachMaintenanceEntryWithDetails(entries), nil } +func isEntryOverdue(completedDate, scheduledDate time.Time) bool { + if scheduledDate.IsZero() { + return false + } + + if completedDate.IsZero() { + return scheduledDate.Before(time.Now()) + } + + return false +} + func (r *MaintenanceEntryRepository) Delete(ctx context.Context, gid uuid.UUID, id uuid.UUID) error { deleted, err := r.db.MaintenanceEntry.Delete().Where( maintenanceentry.ID(id), diff --git a/backend/internal/data/repo/repo_maintenance_entry_test.go b/backend/internal/data/repo/repo_maintenance_entry_test.go index 7f1ff7396..e1bfb0a86 100644 --- a/backend/internal/data/repo/repo_maintenance_entry_test.go +++ b/backend/internal/data/repo/repo_maintenance_entry_test.go @@ -5,8 +5,11 @@ import ( "testing" "time" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" "github.com/sysadminsmedia/homebox/backend/internal/data/types" ) @@ -80,3 +83,144 @@ func TestMaintenanceEntryRepository_GetLog(t *testing.T) { require.NoError(t, err) } } + +func TestMaintenanceEntryRepository_GetLog_Overdue(t *testing.T) { + item := useEntities(t, 1)[0] + + _, err := tRepos.MaintEntry.Create(context.Background(), tGroup.ID, item.ID, MaintenanceEntryCreate{ + ScheduledDate: types.DateFromTime(time.Now().AddDate(0, 0, -2)), + Name: "Filter replacement", + Description: "Overdue task", + Cost: 0, + }) + require.NoError(t, err) + + log, err := tRepos.MaintEntry.GetMaintenanceByItemID( + context.Background(), + tGroup.ID, + item.ID, + MaintenanceFilters{Status: MaintenanceFilterStatusOverdue}, + ) + require.NoError(t, err) + require.Len(t, log, 1) + assert.True(t, log[0].IsOverdue) +} + +func TestMaintenanceEntryRepository_Update_ScheduledCanBeCompleted(t *testing.T) { + item := useEntities(t, 1)[0] + scheduledDate := time.Now().UTC().AddDate(0, 0, 2) + + created, err := tRepos.MaintEntry.Create(context.Background(), tGroup.ID, item.ID, MaintenanceEntryCreate{ + ScheduledDate: types.DateFromTime(scheduledDate), + Name: "Oil change", + Description: "Scheduled maintenance", + Cost: 12.5, + }) + require.NoError(t, err) + + completedDate := types.DateFromTime(time.Now().UTC()) + updated, err := tRepos.MaintEntry.Update(context.Background(), tGroup.ID, created.ID, MaintenanceEntryUpdate{ + Name: created.Name, + Description: created.Description, + Cost: created.Cost, + ScheduledDate: created.ScheduledDate, + CompletedDate: completedDate, + }) + require.NoError(t, err) + assert.Equal(t, completedDate.Time(), updated.CompletedDate.Time()) + assert.Equal(t, created.ScheduledDate.Time(), updated.ScheduledDate.Time()) +} + +func TestMaintenanceEntryRepository_Update_RecurringCompletionCreatesNextEntry(t *testing.T) { + item := useEntities(t, 1)[0] + startDate := time.Now().UTC().AddDate(0, 0, -1) + + plan, err := tRepos.MaintEntry.CreatePlan(context.Background(), item.ID, MaintenancePlanCreate{ + Name: "Filter replacement", + Description: "Recurring filter task", + IntervalValue: 1, + IntervalUnit: MaintenancePlanIntervalUnitMonth, + StartDate: types.DateFromTime(startDate), + Active: true, + }) + require.NoError(t, err) + + initialEntry, err := tRepos.MaintEntry.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.EntityID(item.ID), + maintenanceentry.PlanIDEQ(plan.ID), + ). + Only(context.Background()) + require.NoError(t, err) + + completedAt := types.DateFromTime(time.Now().UTC()) + _, err = tRepos.MaintEntry.Update(context.Background(), tGroup.ID, initialEntry.ID, MaintenanceEntryUpdate{ + Name: initialEntry.Name, + Description: initialEntry.Description, + Cost: initialEntry.Cost, + ScheduledDate: types.DateFromTime(initialEntry.ScheduledDate), + CompletedDate: completedAt, + PlanID: plan.ID, + }) + require.NoError(t, err) + + expectedNextDue := computeNextDue(completedAt.Time(), plan.IntervalValue, plan.IntervalUnit) + + refreshedPlan, err := tRepos.MaintEntry.db.MaintenancePlan.Query(). + Where(maintenanceplan.IDEQ(plan.ID)). + Only(context.Background()) + require.NoError(t, err) + require.NotNil(t, refreshedPlan.NextDueAt) + require.NotNil(t, refreshedPlan.LastCompletedAt) + assert.True(t, expectedNextDue.Equal(*refreshedPlan.NextDueAt)) + assert.True(t, completedAt.Time().Equal(*refreshedPlan.LastCompletedAt)) + + openEntries, err := tRepos.MaintEntry.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.EntityID(item.ID), + maintenanceentry.PlanIDEQ(plan.ID), + maintenanceentry.ScheduledDateEQ(expectedNextDue), + maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), + ), + ). + All(context.Background()) + require.NoError(t, err) + assert.Len(t, openEntries, 1) + + assert.NotEqual(t, uuid.Nil, openEntries[0].ID) + assert.NotEqual(t, initialEntry.ID, openEntries[0].ID) +} + +func TestMaintenanceEntryRepository_CreatePlan_UsesStartDateAsFirstDueDate(t *testing.T) { + item := useEntities(t, 1)[0] + startDate := time.Date(2026, time.March, 10, 9, 30, 0, 0, time.UTC) + expectedFirstDue := types.DateFromTime(startDate).Time() + + plan, err := tRepos.MaintEntry.CreatePlan(context.Background(), item.ID, MaintenancePlanCreate{ + Name: "Weekly maintenance", + Description: "Recurring task with explicit scheduled date", + IntervalValue: 1, + IntervalUnit: MaintenancePlanIntervalUnitWeek, + StartDate: types.DateFromTime(startDate), + Active: true, + }) + require.NoError(t, err) + + assert.True(t, expectedFirstDue.Equal(plan.NextDueAt)) + + openEntries, err := tRepos.MaintEntry.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.EntityID(item.ID), + maintenanceentry.PlanIDEQ(plan.ID), + maintenanceentry.ScheduledDateEQ(expectedFirstDue), + maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), + ), + ). + All(context.Background()) + require.NoError(t, err) + require.Len(t, openEntries, 1) +} diff --git a/backend/internal/data/repo/repo_maintenance_plan.go b/backend/internal/data/repo/repo_maintenance_plan.go new file mode 100644 index 000000000..efe59fb44 --- /dev/null +++ b/backend/internal/data/repo/repo_maintenance_plan.go @@ -0,0 +1,269 @@ +package repo + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/entity" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/group" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceentry" + "github.com/sysadminsmedia/homebox/backend/internal/data/ent/maintenanceplan" + "github.com/sysadminsmedia/homebox/backend/internal/data/types" +) + +type MaintenancePlanIntervalUnit string + +const ( + MaintenancePlanIntervalUnitHour MaintenancePlanIntervalUnit = "hour" + MaintenancePlanIntervalUnitDay MaintenancePlanIntervalUnit = "day" + MaintenancePlanIntervalUnitWeek MaintenancePlanIntervalUnit = "week" + MaintenancePlanIntervalUnitMonth MaintenancePlanIntervalUnit = "month" + MaintenancePlanIntervalUnitYear MaintenancePlanIntervalUnit = "year" +) + +type MaintenancePlanCreate struct { + Name string `json:"name" validate:"required"` + Description string `json:"description"` + IntervalValue int `json:"intervalValue" validate:"required,min=1"` + IntervalUnit MaintenancePlanIntervalUnit `json:"intervalUnit" validate:"required"` + StartDate types.Date `json:"startDate"` + Active bool `json:"active"` + LinkExistingEntryID *uuid.UUID `json:"linkExistingEntryID,omitempty"` +} + +type MaintenancePlanUpdate struct { + Name string `json:"name"` + Description string `json:"description"` + IntervalValue int `json:"intervalValue"` + IntervalUnit MaintenancePlanIntervalUnit `json:"intervalUnit"` + NextDueAt *types.Date `json:"nextDueAt,omitempty"` + Active bool `json:"active"` +} + +type MaintenancePlan struct { + ID uuid.UUID `json:"id"` + ItemID uuid.UUID `json:"itemID"` + Name string `json:"name"` + Description string `json:"description"` + IntervalValue int `json:"intervalValue"` + IntervalUnit MaintenancePlanIntervalUnit `json:"intervalUnit"` + Active bool `json:"active"` + LastCompletedAt time.Time `json:"lastCompletedAt"` + NextDueAt time.Time `json:"nextDueAt"` +} + +func (mc MaintenancePlanCreate) Validate() error { + if mc.IntervalValue < 1 { + return errors.New("intervalValue must be greater than 0") + } + + return validateMaintenancePlanUnit(mc.IntervalUnit) +} + +func (mu MaintenancePlanUpdate) Validate() error { + if mu.IntervalValue < 1 { + return errors.New("intervalValue must be greater than 0") + } + + return validateMaintenancePlanUnit(mu.IntervalUnit) +} + +func validateMaintenancePlanUnit(unit MaintenancePlanIntervalUnit) error { + switch unit { + case MaintenancePlanIntervalUnitHour, + MaintenancePlanIntervalUnitDay, + MaintenancePlanIntervalUnitWeek, + MaintenancePlanIntervalUnitMonth, + MaintenancePlanIntervalUnitYear: + return nil + default: + return errors.New("invalid intervalUnit") + } +} + +func mapMaintenancePlan(entry *ent.MaintenancePlan) MaintenancePlan { + last := time.Time{} + next := time.Time{} + if entry.LastCompletedAt != nil { + last = *entry.LastCompletedAt + } + if entry.NextDueAt != nil { + next = *entry.NextDueAt + } + + return MaintenancePlan{ + ID: entry.ID, + ItemID: entry.EntityID, + Name: entry.Name, + Description: entry.Description, + IntervalValue: entry.IntervalValue, + IntervalUnit: MaintenancePlanIntervalUnit(entry.IntervalUnit), + Active: entry.Active, + LastCompletedAt: last, + NextDueAt: next, + } +} + +func (r *MaintenanceEntryRepository) ListPlansByItemID(ctx context.Context, groupID, itemID uuid.UUID) ([]MaintenancePlan, error) { + items, err := r.db.MaintenancePlan.Query(). + Where( + maintenanceplan.HasEntityWith( + entity.IDEQ(itemID), + entity.HasGroupWith(group.IDEQ(groupID)), + ), + ). + Order(ent.Asc(maintenanceplan.FieldName)). + All(ctx) + if err != nil { + return nil, err + } + + return mapEach(items, mapMaintenancePlan), nil +} + +func (r *MaintenanceEntryRepository) CreatePlan(ctx context.Context, itemID uuid.UUID, input MaintenancePlanCreate) (MaintenancePlan, error) { + base := input.StartDate.Time() + if base.IsZero() { + base = time.Now().UTC() + } + firstDue := base.UTC() + item, err := r.db.MaintenancePlan.Create(). + SetEntityID(itemID). + SetName(input.Name). + SetDescription(input.Description). + SetIntervalValue(input.IntervalValue). + SetIntervalUnit(maintenanceplan.IntervalUnit(input.IntervalUnit)). + SetActive(input.Active). + SetNextDueAt(firstDue). + Save(ctx) + if err != nil { + return MaintenancePlan{}, err + } + + if input.LinkExistingEntryID != nil && *input.LinkExistingEntryID != uuid.Nil { + exists, err := r.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.IDEQ(*input.LinkExistingEntryID), + maintenanceentry.EntityIDEQ(itemID), + ). + Only(ctx) + if err != nil { + return MaintenancePlan{}, fmt.Errorf("link existing maintenance entry: %w", err) + } + _, err = r.db.MaintenanceEntry.UpdateOneID(exists.ID). + SetPlanID(item.ID). + SetScheduledDate(firstDue). + Save(ctx) + if err != nil { + return MaintenancePlan{}, err + } + } else { + _, err = r.db.MaintenanceEntry.Create(). + SetEntityID(itemID). + SetPlanID(item.ID). + SetName(item.Name). + SetDescription(item.Description). + SetScheduledDate(firstDue). + SetDate(time.Time{}). + Save(ctx) + if err != nil { + return MaintenancePlan{}, err + } + } + + return mapMaintenancePlan(item), nil +} + +func (r *MaintenanceEntryRepository) UpdatePlan(ctx context.Context, planID uuid.UUID, input MaintenancePlanUpdate) (MaintenancePlan, error) { + up := r.db.MaintenancePlan.UpdateOneID(planID). + SetName(input.Name). + SetDescription(input.Description). + SetIntervalValue(input.IntervalValue). + SetIntervalUnit(maintenanceplan.IntervalUnit(input.IntervalUnit)). + SetActive(input.Active) + if input.NextDueAt != nil { + t := input.NextDueAt.Time() + if t.IsZero() { + up = up.ClearNextDueAt() + } else { + up = up.SetNextDueAt(t.UTC()) + } + } + + item, err := up.Save(ctx) + if err != nil { + return MaintenancePlan{}, err + } + + return mapMaintenancePlan(item), nil +} + +func (r *MaintenanceEntryRepository) DeletePlan(ctx context.Context, id uuid.UUID) error { + return r.db.MaintenancePlan.DeleteOneID(id).Exec(ctx) +} + +func (r *MaintenanceEntryRepository) rollPlanFromCompletion(ctx context.Context, planID uuid.UUID, completedAt time.Time, itemID uuid.UUID) (MaintenancePlan, error) { + plan, err := r.db.MaintenancePlan.Query().Where(maintenanceplan.IDEQ(planID)).Only(ctx) + if err != nil { + return MaintenancePlan{}, err + } + + nextDue := computeNextDue(completedAt, plan.IntervalValue, MaintenancePlanIntervalUnit(plan.IntervalUnit)) + updated, err := r.db.MaintenancePlan.UpdateOneID(planID). + SetLastCompletedAt(completedAt). + SetNextDueAt(nextDue). + Save(ctx) + if err != nil { + return MaintenancePlan{}, err + } + + openCount, err := r.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.PlanIDEQ(planID), + maintenanceentry.ScheduledDateEQ(nextDue), + maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), + ), + ). + Count(ctx) + if err != nil { + return MaintenancePlan{}, err + } + + if openCount == 0 { + if _, err := r.db.MaintenanceEntry.Create(). + SetEntityID(itemID). + SetPlanID(planID). + SetName(updated.Name). + SetDescription(updated.Description). + SetScheduledDate(nextDue). + SetDate(time.Time{}). + Save(ctx); err != nil { + return MaintenancePlan{}, err + } + } + + return mapMaintenancePlan(updated), nil +} + +func computeNextDue(base time.Time, intervalValue int, intervalUnit MaintenancePlanIntervalUnit) time.Time { + switch intervalUnit { + case MaintenancePlanIntervalUnitHour: + return base.Add(time.Duration(intervalValue) * time.Hour) + case MaintenancePlanIntervalUnitDay: + return base.AddDate(0, 0, intervalValue) + case MaintenancePlanIntervalUnitWeek: + return base.AddDate(0, 0, 7*intervalValue) + case MaintenancePlanIntervalUnitMonth: + return base.AddDate(0, intervalValue, 0) + case MaintenancePlanIntervalUnitYear: + return base.AddDate(intervalValue, 0, 0) + default: + return base + } +} diff --git a/backend/internal/data/repo/repo_maintenance_plan_test.go b/backend/internal/data/repo/repo_maintenance_plan_test.go new file mode 100644 index 000000000..591822ad3 --- /dev/null +++ b/backend/internal/data/repo/repo_maintenance_plan_test.go @@ -0,0 +1,18 @@ +package repo + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestComputeNextDue(t *testing.T) { + base := time.Date(2026, time.January, 1, 10, 0, 0, 0, time.UTC) + + assert.Equal(t, base.Add(2*time.Hour), computeNextDue(base, 2, MaintenancePlanIntervalUnitHour)) + assert.Equal(t, base.AddDate(0, 0, 7), computeNextDue(base, 7, MaintenancePlanIntervalUnitDay)) + assert.Equal(t, base.AddDate(0, 0, 14), computeNextDue(base, 2, MaintenancePlanIntervalUnitWeek)) + assert.Equal(t, base.AddDate(0, 1, 0), computeNextDue(base, 1, MaintenancePlanIntervalUnitMonth)) + assert.Equal(t, base.AddDate(1, 0, 0), computeNextDue(base, 1, MaintenancePlanIntervalUnitYear)) +} diff --git a/frontend/components/Maintenance/EditModal.vue b/frontend/components/Maintenance/EditModal.vue index f839c7b87..ea11e43fd 100644 --- a/frontend/components/Maintenance/EditModal.vue +++ b/frontend/components/Maintenance/EditModal.vue @@ -11,6 +11,28 @@ + +
+ + +
+
+

{{ $t("maintenance.modal.next_scheduled_dates") }}

+
    +
  • + {{ dueDate.toLocaleDateString() }} +
  • +
+
@@ -35,6 +57,10 @@ import { useDialog } from "@/components/ui/dialog-provider"; import FormTextField from "~/components/Form/TextField.vue"; import FormTextArea from "~/components/Form/TextArea.vue"; + import { MaintenancePlanIntervalUnit } from "~~/lib/api/types/data-contracts"; + import type { MaintenanceEntryWithDetails, MaintenancePlanUpdate } from "~~/lib/api/types/data-contracts"; + import { getNextNDueDates } from "~/lib/maintenance/recurrence"; + import { parseDateOnly, toDateOnlyString } from "~/lib/datelib/dateOnly"; import Button from "@/components/ui/button/Button.vue"; const { closeDialog, registerOpenDialogCallback } = useDialog(); @@ -49,9 +75,99 @@ scheduledDate: "", description: "", cost: "", + planID: null as string | null, + isRecurring: false, + intervalValue: "30", + intervalUnit: MaintenancePlanIntervalUnit.Day, itemIds: null as string[] | null, + itemIdForPlanLookup: null as string | null, }); + /** Snapshot when the dialog opened / plan hydrated — used to avoid overwriting plan nextDueAt when unchanged */ + const planFieldBaseline = reactive({ + scheduledDate: "", + completedDate: "", + intervalValue: "30", + intervalUnit: MaintenancePlanIntervalUnit.Day, + }); + + function capturePlanFieldBaseline() { + planFieldBaseline.scheduledDate = entry.scheduledDate; + planFieldBaseline.completedDate = entry.completedDate; + planFieldBaseline.intervalValue = entry.intervalValue; + planFieldBaseline.intervalUnit = entry.intervalUnit; + } + + function sameCalendarDate(a: string, b: string): boolean { + return a === b; + } + + function planScheduleOrRecurrenceChanged(): boolean { + return ( + !sameCalendarDate(entry.scheduledDate, planFieldBaseline.scheduledDate) || + !sameCalendarDate(entry.completedDate, planFieldBaseline.completedDate) || + entry.intervalValue !== planFieldBaseline.intervalValue || + entry.intervalUnit !== planFieldBaseline.intervalUnit + ); + } + + const nextDuePreview = computed(() => { + if (!entry.isRecurring) { + return []; + } + + const intervalValue = Math.max(parseInt(entry.intervalValue, 10) || 1, 1); + const baseDate = parseDateOnly(entry.scheduledDate) ?? parseDateOnly(entry.completedDate) ?? new Date(); + + return getNextNDueDates(baseDate, intervalValue, entry.intervalUnit, 3); + }); + + function getItemIdFromEntry(maintenanceEntry: unknown): string | null { + if (!maintenanceEntry || typeof maintenanceEntry !== "object") { + return null; + } + + const candidate = (maintenanceEntry as MaintenanceEntryWithDetails).itemID; + return typeof candidate === "string" && candidate.length > 0 ? candidate : null; + } + + function normalizePlanId(planId: unknown): string | null { + if (typeof planId !== "string") { + return null; + } + + const normalized = planId.trim().toLowerCase(); + if (!normalized || normalized === "00000000-0000-0000-0000-000000000000") { + return null; + } + + return planId; + } + + async function hydrateRecurringPlan() { + try { + if (!entry.planID || !entry.itemIdForPlanLookup) { + return; + } + + const { data, error } = await api.items.maintenance.getPlans(entry.itemIdForPlanLookup); + if (error || !data) { + return; + } + + const currentPlan = data.find(plan => plan.id === entry.planID); + if (!currentPlan) { + return; + } + + entry.isRecurring = true; + entry.intervalValue = currentPlan.intervalValue.toString(); + entry.intervalUnit = currentPlan.intervalUnit; + } finally { + capturePlanFieldBaseline(); + } + } + async function dispatchFormSubmit() { if (entry.id) { await editEntry(); @@ -66,8 +182,28 @@ return; } + const isRecurring = entry.isRecurring === true; + await Promise.allSettled( entry.itemIds.map(async itemId => { + if (isRecurring) { + const firstDueDate = entry.scheduledDate || entry.completedDate || toDateOnlyString(new Date()); + const { error: planError } = await api.items.maintenance.createPlan(itemId, { + name: entry.name, + description: entry.description, + active: true, + intervalValue: parseInt(entry.intervalValue, 10) || 1, + intervalUnit: entry.intervalUnit, + startDate: firstDueDate, + }); + + if (planError) { + toast.error(t("maintenance.toast.failed_to_create")); + } + + return; + } + const { error } = await api.items.maintenance.create(itemId, { name: entry.name, completedDate: entry.completedDate, @@ -91,10 +227,36 @@ return; } + const isRecurring = entry.isRecurring === true; + const recurringPlanId = entry.planID; + const shouldDisableRecurringPlan = !isRecurring && !!recurringPlanId; + const shouldCreateRecurringPlan = isRecurring && !recurringPlanId && !!entry.itemIdForPlanLookup; + + if (shouldCreateRecurringPlan && entry.itemIdForPlanLookup && entry.id) { + const firstDueDate = entry.scheduledDate || entry.completedDate || toDateOnlyString(new Date()); + const { data: createdPlan, error: createPlanError } = await api.items.maintenance.createPlan(entry.itemIdForPlanLookup, { + name: entry.name, + description: entry.description, + active: true, + intervalValue: Math.max(parseInt(entry.intervalValue, 10) || 1, 1), + intervalUnit: entry.intervalUnit, + startDate: firstDueDate, + linkExistingEntryID: entry.id, + }); + + if (createPlanError || !createdPlan) { + toast.error(t("maintenance.toast.failed_to_update")); + return; + } + + entry.planID = createdPlan.id; + } + const { error } = await api.maintenance.update(entry.id, { name: entry.name, completedDate: entry.completedDate, scheduledDate: entry.scheduledDate, + planID: isRecurring ? entry.planID ?? undefined : undefined, description: entry.description, cost: parseFloat(entry.cost) ? entry.cost : "0", }); @@ -104,6 +266,35 @@ return; } + if (shouldDisableRecurringPlan && recurringPlanId) { + const { error: planDeleteError } = await api.maintenance.deletePlan(recurringPlanId); + if (planDeleteError) { + toast.error(t("maintenance.toast.failed_to_update")); + return; + } + } + + if (isRecurring && entry.planID) { + const intervalValue = Math.max(parseInt(entry.intervalValue, 10) || 1, 1); + const planPayload: MaintenancePlanUpdate = { + name: entry.name, + description: entry.description, + active: true, + intervalValue, + intervalUnit: entry.intervalUnit, + }; + if (planScheduleOrRecurrenceChanged()) { + const firstDueDate = entry.scheduledDate || entry.completedDate || toDateOnlyString(new Date()); + planPayload.nextDueAt = firstDueDate; + } + const { error: planError } = await api.maintenance.updatePlan(entry.planID, planPayload); + + if (planError) { + toast.error(t("maintenance.toast.failed_to_update")); + return; + } + } + closeDialog(DialogID.EditMaintenance, true); } @@ -117,18 +308,30 @@ entry.scheduledDate = ""; entry.description = ""; entry.cost = ""; + entry.isRecurring = false; + entry.intervalValue = "30"; + entry.intervalUnit = MaintenancePlanIntervalUnit.Day; + entry.planID = null; entry.itemIds = typeof params.itemId === "string" ? [params.itemId] : params.itemId; + entry.itemIdForPlanLookup = typeof params.itemId === "string" ? params.itemId : null; break; case "update": entry.id = params.maintenanceEntry.id; entry.name = params.maintenanceEntry.name; - // Backend already returns YYYY-MM-DD via types.Date — keep as string - // so JSON.stringify never converts to a UTC instant. entry.completedDate = (params.maintenanceEntry.completedDate as string) ?? ""; entry.scheduledDate = (params.maintenanceEntry.scheduledDate as string) ?? ""; entry.description = params.maintenanceEntry.description; entry.cost = params.maintenanceEntry.cost; + entry.planID = normalizePlanId(params.maintenanceEntry.planID); + entry.isRecurring = !!entry.planID; + entry.intervalValue = "30"; + entry.intervalUnit = MaintenancePlanIntervalUnit.Day; + entry.itemIdForPlanLookup = params.itemId ?? getItemIdFromEntry(params.maintenanceEntry); entry.itemIds = null; + if (!entry.planID) { + capturePlanFieldBaseline(); + } + void hydrateRecurringPlan(); break; case "duplicate": entry.id = null; @@ -137,7 +340,10 @@ entry.scheduledDate = ""; entry.description = params.maintenanceEntry.description; entry.cost = params.maintenanceEntry.cost; + entry.planID = null; + entry.isRecurring = false; entry.itemIds = [params.itemId]; + entry.itemIdForPlanLookup = params.itemId; break; } }); diff --git a/frontend/components/Maintenance/ListView.vue b/frontend/components/Maintenance/ListView.vue index 6f4a6c00b..f3de70e6e 100644 --- a/frontend/components/Maintenance/ListView.vue +++ b/frontend/components/Maintenance/ListView.vue @@ -1,29 +1,35 @@