From cd16c7247ef5fa48d7fede6c93aa7ca06914831d Mon Sep 17 00:00:00 2001 From: Johann Wagner Date: Thu, 9 Jul 2026 11:35:59 +0200 Subject: [PATCH 1/3] feat: Initial commit for task_groups --- .../down.sql | 16 +++ .../2026-07-09-081408-0000_task_groups/up.sql | 25 +++++ vicky/src/bin/vicky/main.rs | 9 ++ vicky/src/bin/vicky/task_groups.rs | 37 ++++++ vicky/src/bin/vicky/tasks.rs | 4 +- vicky/src/lib/database/entities/mod.rs | 19 +++- vicky/src/lib/database/entities/task.rs | 16 +-- vicky/src/lib/database/entities/task_group.rs | 105 ++++++++++++++++++ vicky/src/lib/database/schema.rs | 18 ++- vicky/src/lib/query/mod.rs | 3 +- 10 files changed, 237 insertions(+), 15 deletions(-) create mode 100644 vicky/migrations/2026-07-09-081408-0000_task_groups/down.sql create mode 100644 vicky/migrations/2026-07-09-081408-0000_task_groups/up.sql create mode 100644 vicky/src/bin/vicky/task_groups.rs create mode 100644 vicky/src/lib/database/entities/task_group.rs diff --git a/vicky/migrations/2026-07-09-081408-0000_task_groups/down.sql b/vicky/migrations/2026-07-09-081408-0000_task_groups/down.sql new file mode 100644 index 0000000..f9d818d --- /dev/null +++ b/vicky/migrations/2026-07-09-081408-0000_task_groups/down.sql @@ -0,0 +1,16 @@ +-- This file should undo anything in `up.sql` + + + +ALTER TABLE tasks + ADD COLUMN "group" VARCHAR; + +UPDATE tasks + SET "group" = tg.name + FROM task_groups tg + WHERE group_id = tg.id; + +ALTER TABLE tasks + DROP COLUMN group_id; + +DROP TABLE task_groups; diff --git a/vicky/migrations/2026-07-09-081408-0000_task_groups/up.sql b/vicky/migrations/2026-07-09-081408-0000_task_groups/up.sql new file mode 100644 index 0000000..e759909 --- /dev/null +++ b/vicky/migrations/2026-07-09-081408-0000_task_groups/up.sql @@ -0,0 +1,25 @@ +-- Your SQL goes here + +create table task_groups +( + id uuid default uuid_generate_v4() not null primary key, + name varchar not null, + created_at timestamp with time zone default now() not null +); + +INSERT INTO task_groups(name) + SELECT DISTINCT "group" from tasks WHERE "group" IS NOT NULL; + +ALTER TABLE tasks + ADD COLUMN "group_id" uuid; + +ALTER TABLE tasks + ADD CONSTRAINT fk_task FOREIGN KEY(group_id) REFERENCES task_groups(id); + + +UPDATE tasks t + SET group_id = tg.id + FROM task_groups tg WHERE t.group = tg.name; + +ALTER TABLE tasks + DROP COLUMN "group"; \ No newline at end of file diff --git a/vicky/src/bin/vicky/main.rs b/vicky/src/bin/vicky/main.rs index 99628d6..3ec25af 100644 --- a/vicky/src/bin/vicky/main.rs +++ b/vicky/src/bin/vicky/main.rs @@ -4,6 +4,7 @@ use crate::locks::{ locks_get_active, locks_get_detailed_poisoned, locks_get_poisoned, locks_unlock, }; use crate::startup::Result; +use crate::task_groups::{task_groups_count, task_groups_get}; use crate::tasks::{ tasks_add, tasks_cancel, tasks_claim, tasks_confirm, tasks_count, tasks_download_logs, tasks_finish, tasks_get, tasks_get_logs, tasks_get_specific, tasks_heartbeat, tasks_put_logs, @@ -36,6 +37,7 @@ mod events; mod locks; mod startup; mod tasks; +mod task_groups; mod user; mod webconfig; @@ -215,6 +217,13 @@ async fn build_web_api( tasks_cancel ], ) + .mount( + "/api/v1/task-groups", + routes![ + task_groups_count, + task_groups_get, + ], + ) .mount( "/api/v1/locks", routes![ diff --git a/vicky/src/bin/vicky/task_groups.rs b/vicky/src/bin/vicky/task_groups.rs new file mode 100644 index 0000000..2ecf109 --- /dev/null +++ b/vicky/src/bin/vicky/task_groups.rs @@ -0,0 +1,37 @@ +use rocket::{get, serde::json::Json}; +use serde::{Deserialize, Serialize}; +use vickylib::database::entities::task_group::TaskGroup; +use vickylib::database::entities::Database; +use vickylib::query::FilterParams; + +use crate::auth::AnyAuthGuard; +use crate::errors::AppError; + + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Count { + count: i64, +} + +#[get("/count")] +pub async fn task_groups_count( + db: Database, + _auth: AnyAuthGuard, +) -> Result, AppError> { + let task_group_count = db.count_all_task_groups().await?; + let c: Count = Count { count: task_group_count }; + Ok(Json(c)) +} + +#[get("/?")] +pub async fn task_groups_get( + db: Database, + _auth: AnyAuthGuard, + filter_params: Option, +) -> Result>, AppError> { + let task_group: Vec = db + .get_task_groups_filtered(filter_params) + .await?; + Ok(Json(task_group)) +} + diff --git a/vicky/src/bin/vicky/tasks.rs b/vicky/src/bin/vicky/tasks.rs index 5876dcf..485dbbc 100644 --- a/vicky/src/bin/vicky/tasks.rs +++ b/vicky/src/bin/vicky/tasks.rs @@ -46,7 +46,7 @@ pub struct RoTaskNew { flake_ref: FlakeRef, locks: Vec, features: HashSet, - group: Option, + group_id: Option, } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -341,7 +341,7 @@ pub async fn tasks_add( .flake_args(task.flake_ref.args) .locks(task.locks) .requires_features(task.features) - .maybe_group(task.group) + .maybe_group_id(task.group_id) .build(); let Ok(task) = task else { diff --git a/vicky/src/lib/database/entities/mod.rs b/vicky/src/lib/database/entities/mod.rs index ac975db..d0a6350 100644 --- a/vicky/src/lib/database/entities/mod.rs +++ b/vicky/src/lib/database/entities/mod.rs @@ -1,11 +1,13 @@ pub mod lock; pub mod task; +pub mod task_group; pub mod user; -use crate::database::entities::lock::PoisonedLock; +use crate::database::entities::{lock::PoisonedLock, task_group::TaskGroup}; use crate::database::entities::lock::db_impl::LockDatabase; use crate::database::entities::task::TaskStatus; use crate::database::entities::task::db_impl::TaskDatabase; +use crate::database::entities::task_group::db_impl::TaskGroupDatabase; use crate::database::entities::user::User; use crate::database::entities::user::db_impl::UserDatabase; use crate::errors::VickyError; @@ -53,6 +55,21 @@ impl Database { pub async fn timeout_task(&self, task_id: Uuid) -> Result; } + #[await(false)] + #[expr(self.run(move |conn| $).await)] + #[through(TaskGroupDatabase)] + to conn { + pub async fn count_all_task_groups( + &self, + ) -> Result; + pub async fn get_task_groups(&self) -> Result, VickyError>; + pub async fn get_task_groups_filtered + Send + 'static>( + &self, + filters: F, + ) -> Result, VickyError>; + } + + #[await(false)] #[expr(self.run(move |conn| $).await)] #[through(LockDatabase)] diff --git a/vicky/src/lib/database/entities/task.rs b/vicky/src/lib/database/entities/task.rs index 5918def..8446000 100644 --- a/vicky/src/lib/database/entities/task.rs +++ b/vicky/src/lib/database/entities/task.rs @@ -87,7 +87,7 @@ pub struct Task { #[serde(with = "ts_seconds_option")] pub last_heartbeat: Option>, - pub group: Option, + pub group_id: Option, } impl Task { @@ -222,7 +222,7 @@ impl From<(DbTask, Vec)> for Task { claimed_at: task.claimed_at, finished_at: task.finished_at, last_heartbeat: task.last_heartbeat, - group: task.group, + group_id: task.group_id, } } } @@ -316,7 +316,7 @@ pub mod db_impl { pub finished_at: Option>, pub last_heartbeat: Option>, - pub group: Option, + pub group_id: Option, } pub const STATE_NEEDS_USER_VALIDATION_STR: &str = "NEEDS_USER_VALIDATION"; @@ -374,7 +374,7 @@ pub mod db_impl { claimed_at: task.claimed_at, finished_at: task.finished_at, last_heartbeat: task.last_heartbeat, - group: task.group, + group_id: task.group_id, } } } @@ -419,8 +419,8 @@ pub mod db_impl { tasks_count_b = tasks_count_b.filter(tasks::status.eq(task_status)) } - if let Some(group) = filters.group { - tasks_count_b = tasks_count_b.filter(tasks::group.eq(group)) + if let Some(group_id) = filters.group_id { + tasks_count_b = tasks_count_b.filter(tasks::group_id.eq(group_id)) } let tasks_count: i64 = tasks_count_b.count().first(self)?; @@ -447,8 +447,8 @@ pub mod db_impl { if let Some(r_offset) = filters.offset { db_tasks_build = db_tasks_build.offset(r_offset) } - if let Some(group) = filters.group { - db_tasks_build = db_tasks_build.filter(tasks::group.eq(group)) + if let Some(group_id) = filters.group_id { + db_tasks_build = db_tasks_build.filter(tasks::group_id.eq(group_id)) } let db_tasks = db_tasks_build diff --git a/vicky/src/lib/database/entities/task_group.rs b/vicky/src/lib/database/entities/task_group.rs new file mode 100644 index 0000000..5516b0e --- /dev/null +++ b/vicky/src/lib/database/entities/task_group.rs @@ -0,0 +1,105 @@ +use chrono::serde::ts_seconds; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct TaskGroup { + pub id: Uuid, + pub name: String, + + #[serde(with = "ts_seconds")] + pub created_at: DateTime, +} + +impl TaskGroup { + fn new>(name: S) -> Self { + Self { + id: Uuid::new_v4(), + name: name.into(), + created_at: Utc::now() + } + } +} + +pub mod db_impl { + use chrono::{DateTime, Utc}; + use diesel::prelude::*; + use serde::Serialize; + use uuid::Uuid; + + use crate::database::entities::task_group::{TaskGroup}; + use crate::database::schema::task_groups; + use crate::errors::VickyError; + use crate::query::FilterParams; + + #[derive(Selectable, Identifiable, Queryable, Debug, Serialize)] + #[diesel(table_name = task_groups)] + pub struct DbTaskGroup { + pub id: Uuid, + pub name: String, + pub created_at: DateTime, + } + + #[derive(Insertable, Debug)] + #[diesel(table_name = task_groups)] + pub struct NewDbTaskGroup { + pub name: String, + } + + impl From for TaskGroup { + fn from(task_group: DbTaskGroup) -> TaskGroup { + TaskGroup { + id: task_group.id, + name: task_group.name, + created_at: Utc::now(), + } + } + } + + pub trait TaskGroupDatabase { + fn get_task_groups(&mut self) -> Result, VickyError>; + fn get_task_groups_filtered>( + &mut self, + filters: F, + ) -> Result, VickyError>; + fn count_all_task_groups(&mut self) -> Result; + } + + impl TaskGroupDatabase for PgConnection { + fn count_all_task_groups(&mut self) -> Result { + let tasks_count_b = task_groups::table.into_boxed(); + let tasks_count: i64 = tasks_count_b.count().first(self)?; + + Ok(tasks_count) + } + + fn get_task_groups_filtered>( + &mut self, + filters: F, + ) -> Result, VickyError> { + let filters = filters.into(); + + let mut db_tasks_build = task_groups::table.into_boxed(); + + if let Some(r_limit) = filters.limit { + db_tasks_build = db_tasks_build.limit(r_limit) + } + if let Some(r_offset) = filters.offset { + db_tasks_build = db_tasks_build.offset(r_offset) + } + let db_task_groups = db_tasks_build + .order(task_groups::created_at.desc()) + .load::(self)?; + + let task_groups: Vec = + db_task_groups.into_iter().map(|t| t.into()).collect(); + + Ok(task_groups) + } + + fn get_task_groups(&mut self) -> Result, VickyError> { + self.get_task_groups_filtered(None) + } + } +} diff --git a/vicky/src/lib/database/schema.rs b/vicky/src/lib/database/schema.rs index 7bf64b5..de78a14 100644 --- a/vicky/src/lib/database/schema.rs +++ b/vicky/src/lib/database/schema.rs @@ -1,5 +1,7 @@ // @generated automatically by Diesel CLI. + + diesel::table! { use diesel::sql_types::*; use crate::database::entities::lock::db_impl::LockKindSqlType; @@ -14,6 +16,14 @@ diesel::table! { } } +diesel::table! { + task_groups (id) { + id -> Uuid, + name -> Varchar, + created_at -> Timestamptz, + } +} + diesel::table! { use diesel::sql_types::*; use crate::database::entities::task::db_impl::TaskStatusSqlType; @@ -26,10 +36,10 @@ diesel::table! { flake_ref_uri -> Varchar, flake_ref_args -> Array, created_at -> Timestamptz, - claimed_at -> Nullable, finished_at -> Nullable, + claimed_at -> Nullable, last_heartbeat -> Nullable, - group -> Nullable, + group_id -> Nullable, } } @@ -44,4 +54,6 @@ diesel::table! { } } -diesel::allow_tables_to_appear_in_same_query!(locks, tasks, users,); +diesel::joinable!(tasks -> task_groups (group_id)); + +diesel::allow_tables_to_appear_in_same_query!(locks, task_groups, tasks, users,); diff --git a/vicky/src/lib/query/mod.rs b/vicky/src/lib/query/mod.rs index 056d247..42114b4 100644 --- a/vicky/src/lib/query/mod.rs +++ b/vicky/src/lib/query/mod.rs @@ -1,10 +1,11 @@ use rocket::FromForm; +use uuid::Uuid; #[derive(FromForm, Default, Clone)] pub struct FilterParams { pub limit: Option, pub offset: Option, - pub group: Option, + pub group_id: Option, } impl From> for FilterParams { From cf6d9f4fd87970fb9ac03809ef4fe93fd7dae8a7 Mon Sep 17 00:00:00 2001 From: Johann Wagner Date: Thu, 9 Jul 2026 13:15:58 +0200 Subject: [PATCH 2/3] feat: Implementing creating task_groups --- vicky/src/bin/vicky/main.rs | 4 +- vicky/src/bin/vicky/task_groups.rs | 47 +++++++++++++++++- vicky/src/lib/database/entities/mod.rs | 2 + vicky/src/lib/database/entities/task_group.rs | 49 ++++++++++++++++++- vicky/src/lib/vicky/events.rs | 1 + 5 files changed, 98 insertions(+), 5 deletions(-) diff --git a/vicky/src/bin/vicky/main.rs b/vicky/src/bin/vicky/main.rs index 3ec25af..d275733 100644 --- a/vicky/src/bin/vicky/main.rs +++ b/vicky/src/bin/vicky/main.rs @@ -4,7 +4,7 @@ use crate::locks::{ locks_get_active, locks_get_detailed_poisoned, locks_get_poisoned, locks_unlock, }; use crate::startup::Result; -use crate::task_groups::{task_groups_count, task_groups_get}; +use crate::task_groups::{task_groups_add, task_groups_count, task_groups_get, task_groups_get_specific}; use crate::tasks::{ tasks_add, tasks_cancel, tasks_claim, tasks_confirm, tasks_count, tasks_download_logs, tasks_finish, tasks_get, tasks_get_logs, tasks_get_specific, tasks_heartbeat, tasks_put_logs, @@ -222,6 +222,8 @@ async fn build_web_api( routes![ task_groups_count, task_groups_get, + task_groups_get_specific, + task_groups_add, ], ) .mount( diff --git a/vicky/src/bin/vicky/task_groups.rs b/vicky/src/bin/vicky/task_groups.rs index 2ecf109..148d2a9 100644 --- a/vicky/src/bin/vicky/task_groups.rs +++ b/vicky/src/bin/vicky/task_groups.rs @@ -1,18 +1,29 @@ +use rocket::{State, post}; use rocket::{get, serde::json::Json}; use serde::{Deserialize, Serialize}; +use tokio::sync::broadcast; +use uuid::Uuid; use vickylib::database::entities::task_group::TaskGroup; use vickylib::database::entities::Database; use vickylib::query::FilterParams; +use vickylib::vicky::events::GlobalEvent; -use crate::auth::AnyAuthGuard; +use crate::auth::{AnyAuthGuard, MachineGuard}; use crate::errors::AppError; - +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct RoTaskGroupNew { + name: String, +} #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Count { count: i64, } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Empty { +} + #[get("/count")] pub async fn task_groups_count( db: Database, @@ -35,3 +46,35 @@ pub async fn task_groups_get( Ok(Json(task_group)) } +#[get("/")] +pub async fn task_groups_get_specific( + id: Uuid, + db: Database, + _auth: AnyAuthGuard, +) -> Result>, AppError> { + let tasks: Option = db.get_task_group(id).await?; + Ok(Json(tasks)) +} + + +#[post("/", data = "")] +pub async fn task_groups_add( + task_group: Json, + db: Database, + _machine: MachineGuard, + global_events: &State>, +) -> Result, AppError> { + + + let task_group_ro = task_group.into_inner(); + + let db_task_group = TaskGroup::new( + task_group_ro.name, + ); + + db.put_task_groups(db_task_group).await?; + + global_events.send(GlobalEvent::TaskGroupAdd)?; + + Ok(Json(Empty{})) +} diff --git a/vicky/src/lib/database/entities/mod.rs b/vicky/src/lib/database/entities/mod.rs index d0a6350..7cec49a 100644 --- a/vicky/src/lib/database/entities/mod.rs +++ b/vicky/src/lib/database/entities/mod.rs @@ -67,6 +67,8 @@ impl Database { &self, filters: F, ) -> Result, VickyError>; + pub async fn get_task_group(&self, task_group_id: Uuid) -> Result, VickyError>; + pub async fn put_task_groups(&self, task_group: TaskGroup) -> Result; } diff --git a/vicky/src/lib/database/entities/task_group.rs b/vicky/src/lib/database/entities/task_group.rs index 5516b0e..c7c4799 100644 --- a/vicky/src/lib/database/entities/task_group.rs +++ b/vicky/src/lib/database/entities/task_group.rs @@ -13,7 +13,7 @@ pub struct TaskGroup { } impl TaskGroup { - fn new>(name: S) -> Self { + pub fn new>(name: S) -> Self { Self { id: Uuid::new_v4(), name: name.into(), @@ -52,18 +52,39 @@ pub mod db_impl { TaskGroup { id: task_group.id, name: task_group.name, - created_at: Utc::now(), + created_at: task_group.created_at, } } } + impl From for DbTaskGroup { + fn from(task: TaskGroup) -> DbTaskGroup { + DbTaskGroup { + id: task.id, + name: task.name, + created_at: task.created_at, + } + } + } + + impl From for NewDbTaskGroup { + fn from(task: TaskGroup) -> NewDbTaskGroup { + NewDbTaskGroup { + name: task.name, + } + } + } + + pub trait TaskGroupDatabase { fn get_task_groups(&mut self) -> Result, VickyError>; + fn get_task_group(&mut self, task_group_id: Uuid) -> Result, VickyError>; fn get_task_groups_filtered>( &mut self, filters: F, ) -> Result, VickyError>; fn count_all_task_groups(&mut self) -> Result; + fn put_task_groups(&mut self, task_group: TaskGroup) -> Result; } impl TaskGroupDatabase for PgConnection { @@ -100,6 +121,30 @@ pub mod db_impl { fn get_task_groups(&mut self) -> Result, VickyError> { self.get_task_groups_filtered(None) + + } + + fn get_task_group(&mut self, task_group_id: Uuid) -> Result, VickyError> { + let db_taskgroup = task_groups::table.filter(task_groups::id.eq(task_group_id)).first::(self); + let db_taskgroup = match db_taskgroup { + Err(diesel::result::Error::NotFound) => return Ok(None), + _ => db_taskgroup?, + }; + + Ok(Some(db_taskgroup.into())) + } + + + fn put_task_groups(&mut self, task_group: TaskGroup) -> Result { + self.transaction(|conn| { + + let db_task_group: NewDbTaskGroup = task_group.into(); + + let rows_updated = diesel::insert_into(task_groups::table) + .values(&db_task_group) + .execute(conn)?; + Ok(rows_updated) + }) } } } diff --git a/vicky/src/lib/vicky/events.rs b/vicky/src/lib/vicky/events.rs index 510ebf0..8d7d8ba 100644 --- a/vicky/src/lib/vicky/events.rs +++ b/vicky/src/lib/vicky/events.rs @@ -5,4 +5,5 @@ use serde::{Deserialize, Serialize}; pub enum GlobalEvent { TaskAdd, TaskUpdate { uuid: uuid::Uuid }, + TaskGroupAdd, } From 4887d333a60dfbb487a01800c1d506fb1d5513c5 Mon Sep 17 00:00:00 2001 From: Johann Wagner Date: Mon, 13 Jul 2026 09:58:08 +0200 Subject: [PATCH 3/3] fix: tasks need a group_id now --- .../down.sql | 4 ++ .../up.sql | 14 ++++++ vicky/src/bin/vicky/tasks.rs | 6 ++- vicky/src/lib/database/entities/task.rs | 4 +- vicky/src/lib/database/schema.rs | 30 +++++++++---- vicky/src/lib/vicky/constraints_helper.rs | 44 +++++++++++++++++++ 6 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/down.sql create mode 100644 vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/up.sql diff --git a/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/down.sql b/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/down.sql new file mode 100644 index 0000000..3363faf --- /dev/null +++ b/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/down.sql @@ -0,0 +1,4 @@ +-- This file should undo anything in `up.sql` + +alter table tasks + alter column group_id drop not null; \ No newline at end of file diff --git a/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/up.sql b/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/up.sql new file mode 100644 index 0000000..68933f0 --- /dev/null +++ b/vicky/migrations/2026-07-13-073201-0000_task-must-have-task-group/up.sql @@ -0,0 +1,14 @@ +-- Your SQL goes here + + +INSERT INTO task_groups(name) + SELECT DISTINCT CONCAT('Group of ', "display_name") as "group" from tasks WHERE "group_id" IS NULL; + +UPDATE tasks t + SET group_id = tg.id + FROM task_groups tg WHERE CONCAT('Group of ', t."display_name") = tg.name; + + +alter table tasks + alter column group_id set not null; + diff --git a/vicky/src/bin/vicky/tasks.rs b/vicky/src/bin/vicky/tasks.rs index 485dbbc..55e8eda 100644 --- a/vicky/src/bin/vicky/tasks.rs +++ b/vicky/src/bin/vicky/tasks.rs @@ -46,7 +46,7 @@ pub struct RoTaskNew { flake_ref: FlakeRef, locks: Vec, features: HashSet, - group_id: Option, + group_id: Uuid, } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -341,7 +341,7 @@ pub async fn tasks_add( .flake_args(task.flake_ref.args) .locks(task.locks) .requires_features(task.features) - .maybe_group_id(task.group_id) + .group_id(task.group_id) .build(); let Ok(task) = task else { @@ -436,6 +436,7 @@ mod tests { .display_name("Test 1") .read_lock("mauz") .write_lock("mauz") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build(); assert!(task.is_err()); } @@ -447,6 +448,7 @@ mod tests { .read_lock("mauz") .read_lock("mauz") .write_lock("delete_everything") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build(); assert!(task.is_ok()) } diff --git a/vicky/src/lib/database/entities/task.rs b/vicky/src/lib/database/entities/task.rs index 8446000..512fd56 100644 --- a/vicky/src/lib/database/entities/task.rs +++ b/vicky/src/lib/database/entities/task.rs @@ -87,7 +87,7 @@ pub struct Task { #[serde(with = "ts_seconds_option")] pub last_heartbeat: Option>, - pub group_id: Option, + pub group_id: Uuid, } impl Task { @@ -316,7 +316,7 @@ pub mod db_impl { pub finished_at: Option>, pub last_heartbeat: Option>, - pub group_id: Option, + pub group_id: Uuid, } pub const STATE_NEEDS_USER_VALIDATION_STR: &str = "NEEDS_USER_VALIDATION"; diff --git a/vicky/src/lib/database/schema.rs b/vicky/src/lib/database/schema.rs index de78a14..9913862 100644 --- a/vicky/src/lib/database/schema.rs +++ b/vicky/src/lib/database/schema.rs @@ -1,17 +1,29 @@ // @generated automatically by Diesel CLI. +pub mod sql_types { + #[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "LockKind_Type"))] + pub struct LockKindType; + #[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "Role_Type"))] + pub struct RoleType; + + #[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "TaskStatus_Type"))] + pub struct TaskStatusType; +} diesel::table! { use diesel::sql_types::*; - use crate::database::entities::lock::db_impl::LockKindSqlType; + use super::sql_types::LockKindType; locks (id) { id -> Uuid, task_id -> Uuid, name -> Varchar, #[sql_name = "type"] - lock_type -> LockKindSqlType, + type_ -> LockKindType, poisoned_by_task -> Nullable, } } @@ -26,31 +38,31 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; - use crate::database::entities::task::db_impl::TaskStatusSqlType; + use super::sql_types::TaskStatusType; tasks (id) { id -> Uuid, display_name -> Varchar, - status -> TaskStatusSqlType, - features -> Array, + status -> TaskStatusType, + features -> Array>, flake_ref_uri -> Varchar, - flake_ref_args -> Array, + flake_ref_args -> Array>, created_at -> Timestamptz, finished_at -> Nullable, claimed_at -> Nullable, last_heartbeat -> Nullable, - group_id -> Nullable, + group_id -> Uuid, } } diesel::table! { use diesel::sql_types::*; - use crate::database::entities::user::db_impl::RoleSqlType; + use super::sql_types::RoleType; users (id) { id -> Uuid, name -> Varchar, - role -> RoleSqlType, + role -> RoleType, } } diff --git a/vicky/src/lib/vicky/constraints_helper.rs b/vicky/src/lib/vicky/constraints_helper.rs index 8ffff04..e2af07d 100644 --- a/vicky/src/lib/vicky/constraints_helper.rs +++ b/vicky/src/lib/vicky/constraints_helper.rs @@ -95,10 +95,12 @@ mod tests { Task::builder() .display_name("Test 1") .status(TaskStatus::Running) + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::Running) + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -112,11 +114,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .read_lock("foo 1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::Running) .read_lock("foo 1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -130,11 +134,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::Running) .write_lock("foo2") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -148,11 +154,13 @@ mod tests { .display_name("Read lock") .status(TaskStatus::Running) .read_lock("shared") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Cleanup lock") .status(TaskStatus::New) .clean_lock("shared") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -173,11 +181,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -192,11 +202,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -212,11 +224,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::New) .requires_feature("huge_cpu") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .requires_feature("huge_cpu") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -232,11 +246,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::New) .requires_feature("huge_cpu") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .requires_feature("huge_cpu") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -253,11 +269,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .write_lock("foo2") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -273,11 +291,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .read_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .read_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -293,11 +313,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::Running) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .read_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -313,6 +335,7 @@ mod tests { .display_name("Test 1") .status(TaskStatus::New) .clean_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -328,11 +351,13 @@ mod tests { .display_name("Test 5") .status(TaskStatus::Finished(TaskResult::Success)) .write_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 1") .status(TaskStatus::New) .clean_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -348,11 +373,13 @@ mod tests { .display_name("Im doing something") .status(TaskStatus::Running) .read_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Cleanup after") .status(TaskStatus::New) .clean_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -373,11 +400,13 @@ mod tests { .display_name("Test 1") .status(TaskStatus::New) .clean_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Test 2") .status(TaskStatus::New) .read_lock("foo1") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -404,11 +433,13 @@ mod tests { .display_name("Cleanup lock A") .status(TaskStatus::New) .clean_lock("lock_a") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Pending lock B") .status(TaskStatus::New) .read_lock("lock_b") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -425,16 +456,19 @@ mod tests { .status(TaskStatus::NeedsUserValidation) .write_lock("lock_a") .read_lock("lock_b") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Task A2") .status(TaskStatus::New) .read_lock("lock_a") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Task B") .status(TaskStatus::New) .read_lock("lock_b") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -450,16 +484,19 @@ mod tests { .display_name("Validation writer") .status(TaskStatus::NeedsUserValidation) .write_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Validation reader") .status(TaskStatus::NeedsUserValidation) .read_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("New reader") .status(TaskStatus::New) .read_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -479,16 +516,19 @@ mod tests { .display_name("Cleanup 1") .status(TaskStatus::New) .clean_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Reader") .status(TaskStatus::New) .read_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("Cleanup 2") .status(TaskStatus::New) .clean_lock("shared_lock") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; @@ -507,6 +547,7 @@ mod tests { Task::builder() .display_name("I need to do something") .write_lock("Entire Prod Cluster") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; let mut poisoned_lock = Lock::write("Entire Prod Cluster"); @@ -524,10 +565,12 @@ mod tests { Task::builder() .display_name("I need to do something") .write_lock("Entire Prod Cluster") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), Task::builder() .display_name("I need to test something") .write_lock("Entire Staging Cluster") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; let mut poisoned_lock = Lock::write("Entire Prod Cluster"); @@ -548,6 +591,7 @@ mod tests { Task::builder() .display_name("I need to do something") .read_lock("Entire Prod Cluster") + .group_id(uuid::uuid!("00000000-0000-0000-0000-000000000000")) .build_expect(), ]; let mut poisoned_lock = Lock::read("Entire Prod Cluster");