From eaa26f9cb5abb18a7db596249ee382ab7421d779 Mon Sep 17 00:00:00 2001 From: vicwiller Date: Mon, 27 Apr 2026 13:18:37 +0000 Subject: [PATCH 1/2] Add maintenance plan feature --- .../handlers/v1/v1_ctrl_maintenance_plan.go | 85 ++ backend/app/api/routes.go | 4 + backend/go.sum | 73 +- backend/internal/data/ent/client.go | 219 ++- backend/internal/data/ent/ent.go | 2 + backend/internal/data/ent/entity.go | 20 +- backend/internal/data/ent/entity/entity.go | 30 + backend/internal/data/ent/entity/where.go | 23 + backend/internal/data/ent/entity_create.go | 32 + backend/internal/data/ent/entity_query.go | 76 +- backend/internal/data/ent/entity_update.go | 163 +++ backend/internal/data/ent/has_id.go | 4 + backend/internal/data/ent/hook/hook.go | 12 + backend/internal/data/ent/maintenanceentry.go | 37 +- .../ent/maintenanceentry/maintenanceentry.go | 31 + .../data/ent/maintenanceentry/where.go | 58 + .../data/ent/maintenanceentry_create.go | 37 + .../data/ent/maintenanceentry_query.go | 80 +- .../data/ent/maintenanceentry_update.go | 121 ++ backend/internal/data/ent/maintenanceplan.go | 261 ++++ .../ent/maintenanceplan/maintenanceplan.go | 222 +++ .../data/ent/maintenanceplan/where.go | 573 ++++++++ .../data/ent/maintenanceplan_create.go | 456 ++++++ .../data/ent/maintenanceplan_delete.go | 88 ++ .../data/ent/maintenanceplan_query.go | 687 +++++++++ .../data/ent/maintenanceplan_update.go | 859 +++++++++++ backend/internal/data/ent/migrate/schema.go | 38 + backend/internal/data/ent/mutation.go | 1271 ++++++++++++++++- .../internal/data/ent/predicate/predicate.go | 3 + backend/internal/data/ent/runtime.go | 56 +- backend/internal/data/ent/schema/entity.go | 1 + .../data/ent/schema/maintenance_entry.go | 7 + .../data/ent/schema/maintenance_plan.go | 74 + backend/internal/data/ent/tx.go | 3 + .../20260424120001_add_maintenance_plans.sql | 29 + .../20260424120000_add_maintenance_plans.sql | 28 + .../internal/data/repo/repo_maintenance.go | 9 + .../data/repo/repo_maintenance_entry.go | 102 +- .../data/repo/repo_maintenance_entry_test.go | 143 ++ .../data/repo/repo_maintenance_plan.go | 244 ++++ .../data/repo/repo_maintenance_plan_test.go | 18 + frontend/components/Maintenance/EditModal.vue | 219 ++- frontend/components/Maintenance/ListView.vue | 157 +- .../components/ui/dialog-provider/utils.ts | 2 +- frontend/lib/api/classes/items.ts | 15 + frontend/lib/api/classes/maintenance.ts | 13 + frontend/lib/api/types/data-contracts.ts | 45 + frontend/lib/maintenance/recurrence.test.ts | 26 + frontend/lib/maintenance/recurrence.ts | 39 + frontend/locales/en.json | 14 +- 50 files changed, 6688 insertions(+), 121 deletions(-) create mode 100644 backend/app/api/handlers/v1/v1_ctrl_maintenance_plan.go create mode 100644 backend/internal/data/ent/maintenanceplan.go create mode 100644 backend/internal/data/ent/maintenanceplan/maintenanceplan.go create mode 100644 backend/internal/data/ent/maintenanceplan/where.go create mode 100644 backend/internal/data/ent/maintenanceplan_create.go create mode 100644 backend/internal/data/ent/maintenanceplan_delete.go create mode 100644 backend/internal/data/ent/maintenanceplan_query.go create mode 100644 backend/internal/data/ent/maintenanceplan_update.go create mode 100644 backend/internal/data/ent/schema/maintenance_plan.go create mode 100644 backend/internal/data/migrations/postgres/20260424120001_add_maintenance_plans.sql create mode 100644 backend/internal/data/migrations/sqlite3/20260424120000_add_maintenance_plans.sql create mode 100644 backend/internal/data/repo/repo_maintenance_plan.go create mode 100644 backend/internal/data/repo/repo_maintenance_plan_test.go create mode 100644 frontend/lib/maintenance/recurrence.test.ts create mode 100644 frontend/lib/maintenance/recurrence.ts 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..c345cdd99 --- /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 6cca1afe9..b90e6cf4d 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -164,6 +164,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...)) @@ -179,6 +181,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 fe3edf563..8b7d43a1c 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -135,12 +135,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/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= @@ -204,10 +198,6 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= -github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= -github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= -github.com/go-openapi/jsonpointer v0.23.0 h1:c25HFTJ6uWGmoe5BQI6p72p4o7KnlWYsy1MeFlAumsw= -github.com/go-openapi/jsonpointer v0.23.0/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= @@ -215,43 +205,26 @@ github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZL github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= -github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= -github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= -github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= -github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= -github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= -github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= -github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= -github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko= github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg= -github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= -github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= -github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= -github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= -github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= -github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= -github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= -github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= +github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -296,8 +269,6 @@ github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8= github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= -github.com/googleapis/gax-go/v2 v2.21.0 h1:h45NjjzEO3faG9Lg/cFrBh2PgegVVgzqKzuZl/wMbiI= -github.com/googleapis/gax-go/v2 v2.21.0/go.mod h1:But/NJU6TnZsrLai/xBAQLLz+Hc7fHZJt/hsCz3Fih4= github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= @@ -306,8 +277,6 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -323,8 +292,6 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc= -github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= @@ -365,8 +332,6 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= @@ -379,8 +344,6 @@ github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= github.com/nats-io/nats-server/v2 v2.11.12 h1:jGDXTkcjqQ5fCRstwIxvv1K0RHfftFUoSCT/iIZcqOc= github.com/nats-io/nats-server/v2 v2.11.12/go.mod h1:5MCp/pqm5SEfsvVZ31ll1088ZTwEUdvRX1Hmh/mTTDg= -github.com/nats-io/nats.go v1.50.0 h1:5zAeQrTvyrKrWLJ0fu02W3br8ym57qf7csDzgLOpcds= -github.com/nats-io/nats.go v1.50.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI= github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= @@ -391,14 +354,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= @@ -430,8 +385,6 @@ github.com/riandyrn/otelchi v0.12.2 h1:6QhGv0LVw/dwjtPd12mnNrl0oEQF4ZAlmHcnlTYbe github.com/riandyrn/otelchi v0.12.2/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI= -github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM= @@ -444,10 +397,6 @@ github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfx github.com/shirou/gopsutil/v4 v4.26.3/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= @@ -470,8 +419,6 @@ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA= github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU= -github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= -github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= @@ -619,22 +566,12 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.275.0 h1:vfY5d9vFVJeWEZT65QDd9hbndr7FyZ2+6mIzGAh71NI= -google.golang.org/api v0.275.0/go.mod h1:Fnag/EWUPIcJXuIkP1pjoTgS5vdxlk3eeemL7Do6bvw= google.golang.org/api v0.276.0 h1:nVArUtfLEihtW+b0DdcqRGK1xoEm2+ltAihyztq7MKY= google.golang.org/api v0.276.0/go.mod h1:Fnag/EWUPIcJXuIkP1pjoTgS5vdxlk3eeemL7Do6bvw= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d h1:/aDRtSZJjyLQzm75d+a1wOJaqyKBMvIAfeQmoa3ORiI= -google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:etfGUgejTiadZAUaEP14NP97xi1RGeawqkjDARA/UOs= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529 h1:zUWMZsvo/IJcD1t6MNCPO/azZTwz0TvwCBqr5aifoVY= google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529/go.mod h1:a5OGAgyRr4lqco7AG9hQM9Fwh0N2ZV4grR0eXFEsXQg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d h1:wT2n40TBqFY6wiwazVK9/iTWbsQrgk5ZfCSVFLO9LQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= @@ -660,8 +597,6 @@ modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.71.0 h1:bu0djXJGhqed3DnBzyzu3sY0fv432lesyz99ecEahyA= -modernc.org/libc v1.71.0/go.mod h1:tTU8DL8A+XLVkEY3x5E/tO7s2Q/q42EtnNWda/L5QhQ= modernc.org/libc v1.72.0 h1:IEu559v9a0XWjw0DPoVKtXpO2qt5NVLAnFaBbjq+n8c= modernc.org/libc v1.72.0/go.mod h1:tTU8DL8A+XLVkEY3x5E/tO7s2Q/q42EtnNWda/L5QhQ= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= @@ -672,8 +607,6 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c= -modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= modernc.org/sqlite v1.49.1 h1:dYGHTKcX1sJ+EQDnUzvz4TJ5GbuvhNJa8Fg6ElGx73U= modernc.org/sqlite v1.49.1/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= diff --git a/backend/internal/data/ent/client.go b/backend/internal/data/ent/client.go index 9ff6e8884..705886038 100644 --- a/backend/internal/data/ent/client.go +++ b/backend/internal/data/ent/client.go @@ -26,6 +26,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/tag" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/templatefield" @@ -57,6 +58,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 // Tag is the client for interacting with the Tag builders. @@ -86,6 +89,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.Tag = NewTagClient(c.config) c.TemplateField = NewTemplateFieldClient(c.config) @@ -192,6 +196,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), Tag: NewTagClient(cfg), TemplateField: NewTemplateFieldClient(cfg), @@ -225,6 +230,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), Tag: NewTagClient(cfg), TemplateField: NewTemplateFieldClient(cfg), @@ -260,7 +266,8 @@ func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ c.Attachment, c.AuthRoles, c.AuthTokens, c.Entity, c.EntityField, c.EntityTemplate, c.EntityType, c.Group, c.GroupInvitationToken, - c.MaintenanceEntry, c.Notifier, c.Tag, c.TemplateField, c.User, + c.MaintenanceEntry, c.MaintenancePlan, c.Notifier, c.Tag, c.TemplateField, + c.User, } { n.Use(hooks...) } @@ -272,7 +279,8 @@ func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ c.Attachment, c.AuthRoles, c.AuthTokens, c.Entity, c.EntityField, c.EntityTemplate, c.EntityType, c.Group, c.GroupInvitationToken, - c.MaintenanceEntry, c.Notifier, c.Tag, c.TemplateField, c.User, + c.MaintenanceEntry, c.MaintenancePlan, c.Notifier, c.Tag, c.TemplateField, + c.User, } { n.Intercept(interceptors...) } @@ -301,6 +309,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 *TagMutation: @@ -1013,6 +1023,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() @@ -2083,6 +2109,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 @@ -2108,6 +2150,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 @@ -2804,12 +3011,12 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error) type ( hooks struct { Attachment, AuthRoles, AuthTokens, Entity, EntityField, EntityTemplate, - EntityType, Group, GroupInvitationToken, MaintenanceEntry, Notifier, Tag, - TemplateField, User []ent.Hook + EntityType, Group, GroupInvitationToken, MaintenanceEntry, MaintenancePlan, + Notifier, Tag, TemplateField, User []ent.Hook } inters struct { Attachment, AuthRoles, AuthTokens, Entity, EntityField, EntityTemplate, - EntityType, Group, GroupInvitationToken, MaintenanceEntry, Notifier, Tag, - TemplateField, User []ent.Interceptor + EntityType, Group, GroupInvitationToken, MaintenanceEntry, MaintenancePlan, + Notifier, Tag, TemplateField, User []ent.Interceptor } ) diff --git a/backend/internal/data/ent/ent.go b/backend/internal/data/ent/ent.go index 72e6d381c..0026caf8d 100644 --- a/backend/internal/data/ent/ent.go +++ b/backend/internal/data/ent/ent.go @@ -22,6 +22,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/tag" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/templatefield" @@ -96,6 +97,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, tag.Table: tag.ValidColumn, templatefield.Table: templatefield.ValidColumn, diff --git a/backend/internal/data/ent/entity.go b/backend/internal/data/ent/entity.go index b3260f334..d205f61ba 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 1959a7319..b57697a7e 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 0dfde99e4..2b9d5931b 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 ba2e4ce6d..2f43f6e60 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 7a404a84b..47a3f0c68 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 1e4d0b6c4..f5958f317 100644 --- a/backend/internal/data/ent/has_id.go +++ b/backend/internal/data/ent/has_id.go @@ -44,6 +44,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 e680552da..0b01f5da3 100644 --- a/backend/internal/data/ent/hook/hook.go +++ b/backend/internal/data/ent/hook/hook.go @@ -129,6 +129,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 b0288dc3b..4fb8694c1 100644 --- a/backend/internal/data/ent/migrate/schema.go +++ b/backend/internal/data/ent/migrate/schema.go @@ -339,6 +339,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{ @@ -352,6 +353,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.Cascade, + }, + }, + } + // 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. @@ -559,6 +594,7 @@ var ( GroupsTable, GroupInvitationTokensTable, MaintenanceEntriesTable, + MaintenancePlansTable, NotifiersTable, TagsTable, TemplateFieldsTable, @@ -583,6 +619,8 @@ func init() { EntityTypesTable.ForeignKeys[1].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 TagsTable.ForeignKeys[0].RefTable = GroupsTable diff --git a/backend/internal/data/ent/mutation.go b/backend/internal/data/ent/mutation.go index 3ec8dd007..43cb48512 100644 --- a/backend/internal/data/ent/mutation.go +++ b/backend/internal/data/ent/mutation.go @@ -22,6 +22,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/predicate" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" @@ -48,6 +49,7 @@ const ( TypeGroup = "Group" TypeGroupInvitationToken = "GroupInvitationToken" TypeMaintenanceEntry = "MaintenanceEntry" + TypeMaintenancePlan = "MaintenancePlan" TypeNotifier = "Notifier" TypeTag = "Tag" TypeTemplateField = "TemplateField" @@ -1902,6 +1904,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 @@ -3460,6 +3465,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 { @@ -4170,7 +4229,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) } @@ -4192,6 +4251,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) } @@ -4238,6 +4300,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 { @@ -4250,7 +4318,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) } @@ -4263,6 +4331,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) } @@ -4297,6 +4368,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 { @@ -4309,7 +4386,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) } @@ -4331,6 +4408,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) } @@ -4355,6 +4435,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 } @@ -4403,6 +4485,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 @@ -9560,6 +9645,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 @@ -9777,6 +9864,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 @@ -10043,6 +10179,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...) @@ -10077,7 +10240,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) } @@ -10087,6 +10250,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) } @@ -10116,6 +10282,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: @@ -10141,6 +10309,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: @@ -10181,6 +10351,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 { @@ -10261,6 +10438,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) } @@ -10284,6 +10464,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 @@ -10310,6 +10493,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 @@ -10331,10 +10517,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 } @@ -10346,13 +10535,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 } @@ -10364,10 +10557,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 } @@ -10377,6 +10573,8 @@ func (m *MaintenanceEntryMutation) EdgeCleared(name string) bool { switch name { case maintenanceentry.EdgeEntity: return m.clearedentity + case maintenanceentry.EdgePlan: + return m.clearedplan } return false } @@ -10388,6 +10586,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) } @@ -10399,10 +10600,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 3a5e59df9..42d53dcbe 100644 --- a/backend/internal/data/ent/predicate/predicate.go +++ b/backend/internal/data/ent/predicate/predicate.go @@ -36,6 +36,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 ef6c1bcb8..f34b19e62 100644 --- a/backend/internal/data/ent/runtime.go +++ b/backend/internal/data/ent/runtime.go @@ -15,6 +15,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/schema" "github.com/sysadminsmedia/homebox/backend/internal/data/ent/tag" @@ -470,7 +471,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 @@ -488,17 +489,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 fa441ed19..ed4a35de9 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..95b2d0a50 --- /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.Cascade, + }), + } +} diff --git a/backend/internal/data/ent/tx.go b/backend/internal/data/ent/tx.go index 1648548cd..923801014 100644 --- a/backend/internal/data/ent/tx.go +++ b/backend/internal/data/ent/tx.go @@ -32,6 +32,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 // Tag is the client for interacting with the Tag builders. @@ -181,6 +183,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.Tag = NewTagClient(tx.config) tx.TemplateField = NewTemplateFieldClient(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..7c586cb5d --- /dev/null +++ b/backend/internal/data/migrations/postgres/20260424120001_add_maintenance_plans.sql @@ -0,0 +1,29 @@ +-- +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; + +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 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..59f093bb5 --- /dev/null +++ b/backend/internal/data/migrations/sqlite3/20260424120000_add_maintenance_plans.sql @@ -0,0 +1,28 @@ +-- +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); + +ALTER TABLE maintenance_entries + ADD COLUMN plan_id uuid; + +CREATE INDEX idx_maintenance_entries_plan_id ON maintenance_entries (plan_id); + +-- +goose Down +DROP INDEX IF EXISTS idx_maintenance_entries_plan_id; +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 b4d718376..99c00ab87 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, @@ -108,18 +118,73 @@ func (r *MaintenanceEntryRepository) Create(ctx context.Context, itemID uuid.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, id uuid.UUID, input MaintenanceEntryUpdate) (MaintenanceEntry, error) { - 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) + current, err := r.db.MaintenanceEntry.Query().Where(maintenanceentry.IDEQ(id)).Only(ctx) + if err != nil { + return MaintenanceEntry{}, err + } + + completedDate := input.CompletedDate.Time() + if completedDate.IsZero() { + completedDate = current.Date + } + + 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) } @@ -153,6 +218,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( @@ -169,6 +245,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, id uuid.UUID) error { return r.db.MaintenanceEntry.DeleteOneID(id).Exec(ctx) } diff --git a/backend/internal/data/repo/repo_maintenance_entry_test.go b/backend/internal/data/repo/repo_maintenance_entry_test.go index d5b3c041a..7e2a706ae 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,143 @@ 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(), 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(), 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(), 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: 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(), 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) + + 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: startDate, + Active: true, + }) + require.NoError(t, err) + + assert.Equal(t, startDate, plan.NextDueAt) + + openEntries, err := tRepos.MaintEntry.db.MaintenanceEntry.Query(). + Where( + maintenanceentry.EntityID(item.ID), + maintenanceentry.PlanIDEQ(plan.ID), + maintenanceentry.ScheduledDateEQ(startDate), + 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..ca156fa58 --- /dev/null +++ b/backend/internal/data/repo/repo_maintenance_plan.go @@ -0,0 +1,244 @@ +package repo + +import ( + "context" + "errors" + "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" +) + +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 time.Time `json:"startDate"` + Active bool `json:"active"` +} + +type MaintenancePlanUpdate struct { + Name string `json:"name"` + Description string `json:"description"` + IntervalValue int `json:"intervalValue"` + IntervalUnit MaintenancePlanIntervalUnit `json:"intervalUnit"` + NextDueAt time.Time `json:"nextDueAt"` + 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 + 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 + } + + _, 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.IsZero() { + up = up.ClearNextDueAt() + } else { + up = up.SetNextDueAt(input.NextDueAt) + } + + 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 45157ed0c..2ec1fd07d 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,9 @@ import { useDialog } from "@/components/ui/dialog-provider"; import FormTextField from "~/components/Form/TextField.vue"; import FormTextArea from "~/components/Form/TextArea.vue"; + import { MaintenanceFilterStatus, MaintenancePlanIntervalUnit } from "~~/lib/api/types/data-contracts"; + import type { MaintenanceEntryWithDetails } from "~~/lib/api/types/data-contracts"; + import { getNextNDueDates } from "~/lib/maintenance/recurrence"; import Button from "@/components/ui/button/Button.vue"; const { closeDialog, registerOpenDialogCallback } = useDialog(); @@ -49,9 +74,87 @@ scheduledDate: null as Date | null, description: "", cost: "", + planID: null as string | null, + isRecurring: false, + intervalValue: "30", + intervalUnit: MaintenancePlanIntervalUnit.Day, itemIds: null as string[] | null, + itemIdForPlanLookup: null as string | null, }); + const nextDuePreview = computed(() => { + if (!entry.isRecurring) { + return []; + } + + const intervalValue = Math.max(parseInt(entry.intervalValue, 10) || 1, 1); + const baseDate = entry.scheduledDate ?? entry.completedDate ?? new Date(Date.now()); + + 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 parseDateOrNull(value: Date | string | null | undefined): Date | null { + if (!value) { + return null; + } + + const parsed = new Date(value); + return Number.isNaN(parsed.getTime()) ? null : parsed; + } + + 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; + } + + function dateToApiValue(value: Date | null, nullFallback: "null" | ""): string { + if (!value) { + return nullFallback; + } + + const year = value.getFullYear(); + const month = `${value.getMonth() + 1}`.padStart(2, "0"); + const day = `${value.getDate()}`.padStart(2, "0"); + return `${year}-${month}-${day}`; + } + + async function hydrateRecurringPlan() { + 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; + } + async function dispatchFormSubmit() { if (entry.id) { await editEntry(); @@ -66,12 +169,32 @@ return; } + const isRecurring = entry.isRecurring === true; + await Promise.allSettled( entry.itemIds.map(async itemId => { + if (isRecurring) { + const firstDueDate = entry.scheduledDate ?? entry.completedDate ?? new Date(Date.now()); + 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 ?? "", - scheduledDate: entry.scheduledDate ?? "", + completedDate: dateToApiValue(entry.completedDate, ""), + scheduledDate: dateToApiValue(entry.scheduledDate, ""), description: entry.description, cost: parseFloat(entry.cost) ? entry.cost : "0", }); @@ -91,10 +214,37 @@ return; } + const isRecurring = entry.isRecurring === true; + const recurringPlanId = entry.planID; + const shouldDisableRecurringPlan = !isRecurring && !!recurringPlanId; + const shouldCreateRecurringPlan = isRecurring && !recurringPlanId && !!entry.itemIdForPlanLookup; + let createdPlanId: string | null = null; + + if (shouldCreateRecurringPlan && entry.itemIdForPlanLookup) { + const firstDueDate = entry.scheduledDate ?? entry.completedDate ?? new Date(Date.now()); + 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, + }); + + if (createPlanError || !createdPlan) { + toast.error(t("maintenance.toast.failed_to_update")); + return; + } + + createdPlanId = createdPlan.id; + entry.planID = createdPlan.id; + } + const { error } = await api.maintenance.update(entry.id, { name: entry.name, - completedDate: entry.completedDate ?? "null", - scheduledDate: entry.scheduledDate ?? "null", + completedDate: dateToApiValue(entry.completedDate, "null"), + scheduledDate: dateToApiValue(entry.scheduledDate, "null"), + planID: isRecurring ? entry.planID ?? undefined : undefined, description: entry.description, cost: entry.cost, }); @@ -104,6 +254,49 @@ return; } + if (createdPlanId && entry.itemIdForPlanLookup) { + const { data: logData, error: logError } = await api.items.maintenance.getLog(entry.itemIdForPlanLookup, { + status: MaintenanceFilterStatus.MaintenanceFilterStatusBoth, + }); + + if (!logError && logData) { + const autoCreatedEntry = logData.find(logEntry => logEntry.planID === createdPlanId && logEntry.id !== entry.id); + if (autoCreatedEntry) { + const { error: deleteError } = await api.maintenance.delete(autoCreatedEntry.id); + if (deleteError) { + toast.error(t("maintenance.toast.failed_to_update")); + 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 firstDueDate = entry.scheduledDate ?? entry.completedDate ?? new Date(Date.now()); + const { error: planError } = await api.maintenance.updatePlan(entry.planID, { + name: entry.name, + description: entry.description, + active: true, + intervalValue, + intervalUnit: entry.intervalUnit, + nextDueAt: firstDueDate, + }); + + if (planError) { + toast.error(t("maintenance.toast.failed_to_update")); + return; + } + } + closeDialog(DialogID.EditMaintenance, true); } @@ -117,16 +310,27 @@ entry.scheduledDate = null; 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; - entry.completedDate = new Date(params.maintenanceEntry.completedDate); - entry.scheduledDate = new Date(params.maintenanceEntry.scheduledDate); + entry.completedDate = parseDateOrNull(params.maintenanceEntry.completedDate); + entry.scheduledDate = parseDateOrNull(params.maintenanceEntry.scheduledDate); 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; + void hydrateRecurringPlan(); break; case "duplicate": entry.id = null; @@ -135,7 +339,10 @@ entry.scheduledDate = null; 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 1b8ae2967..36b9c2568 100644 --- a/frontend/components/Maintenance/ListView.vue +++ b/frontend/components/Maintenance/ListView.vue @@ -1,25 +1,30 @@