From 71bbaaeae06cafbbfff508fd350f53cb70332c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 18 Sep 2024 21:11:54 +0200 Subject: [PATCH] Manager; convert fetching of sleep schedules to sqlc This also corrects the sleep schedule schema to actually store the `is_active` field as `boolean` (it was `numeric`, which is the same underlying field type in SQLite, but produces a different struct field in the sqlc-generated Go code). Ref: #104305 --- .../migrations/0006_numeric_to_boolean.sql | 57 +++++++++++++++++++ internal/manager/persistence/sqlc/models.go | 2 +- .../persistence/sqlc/query_workers.sql | 6 ++ .../persistence/sqlc/query_workers.sql.go | 24 ++++++++ internal/manager/persistence/sqlc/schema.sql | 2 +- .../persistence/worker_sleep_schedule.go | 48 ++++++++++++---- 6 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 internal/manager/persistence/migrations/0006_numeric_to_boolean.sql diff --git a/internal/manager/persistence/migrations/0006_numeric_to_boolean.sql b/internal/manager/persistence/migrations/0006_numeric_to_boolean.sql new file mode 100644 index 00000000..d4cd519e --- /dev/null +++ b/internal/manager/persistence/migrations/0006_numeric_to_boolean.sql @@ -0,0 +1,57 @@ +-- Some booleans were modeled as `numeric`. These are turned into `boolean` instead. +-- +-- +goose Up +CREATE TABLE temp_sleep_schedules ( + id integer NOT NULL, + created_at datetime NOT NULL, + updated_at datetime, + worker_id integer UNIQUE DEFAULT 0 NOT NULL, + is_active boolean DEFAULT false NOT NULL, + days_of_week text DEFAULT '' NOT NULL, + start_time text DEFAULT '' NOT NULL, + end_time text DEFAULT '' NOT NULL, + next_check datetime, + PRIMARY KEY (id), + CONSTRAINT fk_sleep_schedules_worker FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE +); +INSERT INTO temp_sleep_schedules SELECT + id, + created_at, + updated_at, + worker_id, + is_active, + days_of_week, + start_time, + end_time, + next_check +FROM sleep_schedules; +DROP TABLE sleep_schedules; +ALTER TABLE temp_sleep_schedules RENAME TO sleep_schedules; + +-- +goose Down +CREATE TABLE temp_sleep_schedules ( + id integer NOT NULL, + created_at datetime NOT NULL, + updated_at datetime, + worker_id integer UNIQUE DEFAULT 0 NOT NULL, + is_active numeric DEFAULT false NOT NULL, + days_of_week text DEFAULT '' NOT NULL, + start_time text DEFAULT '' NOT NULL, + end_time text DEFAULT '' NOT NULL, + next_check datetime, + PRIMARY KEY (id), + CONSTRAINT fk_sleep_schedules_worker FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE +); +INSERT INTO temp_sleep_schedules SELECT + id, + created_at, + updated_at, + worker_id, + is_active, + days_of_week, + start_time, + end_time, + next_check +FROM sleep_schedules; +DROP TABLE sleep_schedules; +ALTER TABLE temp_sleep_schedules RENAME TO sleep_schedules; diff --git a/internal/manager/persistence/sqlc/models.go b/internal/manager/persistence/sqlc/models.go index e49ff97f..adf46184 100644 --- a/internal/manager/persistence/sqlc/models.go +++ b/internal/manager/persistence/sqlc/models.go @@ -47,7 +47,7 @@ type SleepSchedule struct { CreatedAt time.Time UpdatedAt sql.NullTime WorkerID int64 - IsActive float64 + IsActive bool DaysOfWeek string StartTime string EndTime string diff --git a/internal/manager/persistence/sqlc/query_workers.sql b/internal/manager/persistence/sqlc/query_workers.sql index db537b23..64cc7974 100644 --- a/internal/manager/persistence/sqlc/query_workers.sql +++ b/internal/manager/persistence/sqlc/query_workers.sql @@ -160,3 +160,9 @@ WHERE last_seen_at <= @last_seen_before AND deleted_at IS NULL AND status NOT IN (sqlc.slice('worker_statuses_no_timeout')); + +-- name: FetchWorkerSleepSchedule :one +SELECT sleep_schedules.* +FROM sleep_schedules +INNER JOIN workers on workers.id = sleep_schedules.worker_id +WHERE workers.uuid = @workerUUID; diff --git a/internal/manager/persistence/sqlc/query_workers.sql.go b/internal/manager/persistence/sqlc/query_workers.sql.go index 7d6012f3..c2385c51 100644 --- a/internal/manager/persistence/sqlc/query_workers.sql.go +++ b/internal/manager/persistence/sqlc/query_workers.sql.go @@ -276,6 +276,30 @@ func (q *Queries) FetchWorker(ctx context.Context, uuid string) (Worker, error) return i, err } +const fetchWorkerSleepSchedule = `-- name: FetchWorkerSleepSchedule :one +SELECT sleep_schedules.id, sleep_schedules.created_at, sleep_schedules.updated_at, sleep_schedules.worker_id, sleep_schedules.is_active, sleep_schedules.days_of_week, sleep_schedules.start_time, sleep_schedules.end_time, sleep_schedules.next_check +FROM sleep_schedules +INNER JOIN workers on workers.id = sleep_schedules.worker_id +WHERE workers.uuid = ?1 +` + +func (q *Queries) FetchWorkerSleepSchedule(ctx context.Context, workeruuid string) (SleepSchedule, error) { + row := q.db.QueryRowContext(ctx, fetchWorkerSleepSchedule, workeruuid) + var i SleepSchedule + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.WorkerID, + &i.IsActive, + &i.DaysOfWeek, + &i.StartTime, + &i.EndTime, + &i.NextCheck, + ) + return i, err +} + const fetchWorkerTagByID = `-- name: FetchWorkerTagByID :one SELECT id, created_at, updated_at, uuid, name, description FROM worker_tags diff --git a/internal/manager/persistence/sqlc/schema.sql b/internal/manager/persistence/sqlc/schema.sql index b5f7c3de..35d283a2 100644 --- a/internal/manager/persistence/sqlc/schema.sql +++ b/internal/manager/persistence/sqlc/schema.sql @@ -39,7 +39,7 @@ CREATE TABLE sleep_schedules ( created_at datetime NOT NULL, updated_at datetime, worker_id integer UNIQUE DEFAULT 0 NOT NULL, - is_active numeric DEFAULT false NOT NULL, + is_active boolean DEFAULT false NOT NULL, days_of_week text DEFAULT '' NOT NULL, start_time text DEFAULT '' NOT NULL, end_time text DEFAULT '' NOT NULL, diff --git a/internal/manager/persistence/worker_sleep_schedule.go b/internal/manager/persistence/worker_sleep_schedule.go index 4fa40122..8ac9bf83 100644 --- a/internal/manager/persistence/worker_sleep_schedule.go +++ b/internal/manager/persistence/worker_sleep_schedule.go @@ -4,11 +4,14 @@ package persistence import ( "context" + "database/sql" + "errors" "fmt" "time" "github.com/rs/zerolog/log" "gorm.io/gorm/clause" + "projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc" ) // SleepSchedule belongs to a Worker, and determines when it's automatically @@ -37,19 +40,17 @@ func (db *DB) FetchWorkerSleepSchedule(ctx context.Context, workerUUID string) ( logger := log.With().Str("worker", workerUUID).Logger() logger.Trace().Msg("fetching worker sleep schedule") - var sched SleepSchedule - tx := db.gormDB.WithContext(ctx). - Joins("inner join workers on workers.id = sleep_schedules.worker_id"). - Where("workers.uuid = ?", workerUUID). - // This is the same as First(&sched), except it doesn't cause an error if it doesn't exist: - Limit(1).Find(&sched) - if tx.Error != nil { - return nil, tx.Error - } - if sched.ID == 0 { + queries := db.queries() + + sqlcSched, err := queries.FetchWorkerSleepSchedule(ctx, workerUUID) + switch { + case errors.Is(err, sql.ErrNoRows): return nil, nil + case err != nil: + return nil, err } - return &sched, nil + + return convertSqlcSleepSchedule(sqlcSched) } func (db *DB) SetWorkerSleepSchedule(ctx context.Context, workerUUID string, schedule *SleepSchedule) error { @@ -125,3 +126,28 @@ func (db *DB) FetchSleepSchedulesToCheck(ctx context.Context) ([]*SleepSchedule, } return schedules, nil } + +func convertSqlcSleepSchedule(sqlcSchedule sqlc.SleepSchedule) (*SleepSchedule, error) { + schedule := SleepSchedule{ + Model: Model{ + ID: uint(sqlcSchedule.ID), + CreatedAt: sqlcSchedule.CreatedAt, + UpdatedAt: sqlcSchedule.UpdatedAt.Time, + }, + WorkerID: uint(sqlcSchedule.WorkerID), + IsActive: sqlcSchedule.IsActive, + DaysOfWeek: sqlcSchedule.DaysOfWeek, + } + + err := schedule.StartTime.Scan(sqlcSchedule.StartTime) + if err != nil { + return nil, fmt.Errorf("parsing schedule start time %q: %w", sqlcSchedule.StartTime, err) + } + + err = schedule.EndTime.Scan(sqlcSchedule.EndTime) + if err != nil { + return nil, fmt.Errorf("parsing schedule end time %q: %w", sqlcSchedule.EndTime, err) + } + + return &schedule, nil +}