diff --git a/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/down.sql b/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/up.sql b/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/up.sql deleted file mode 100644 index b37f10d95f..0000000000 --- a/_sql/migrations/2025-07-23-031628_alter_prompts_add_service/up.sql +++ /dev/null @@ -1 +0,0 @@ --- Your SQL goes here diff --git a/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/down.sql b/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/down.sql index d9a93fe9a1..8418efe04a 100644 --- a/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/down.sql +++ b/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/down.sql @@ -1 +1,5 @@ --- This file should undo anything in `up.sql` +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts DROP COLUMN maybe_model_type; diff --git a/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/up.sql b/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/up.sql index b37f10d95f..b371789846 100644 --- a/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/up.sql +++ b/_sql/migrations/2025-07-23-031631_alter_prompts_add_model/up.sql @@ -1 +1,6 @@ --- Your SQL goes here +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts + ADD COLUMN maybe_model_type VARCHAR(32) DEFAULT NULL; diff --git a/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/down.sql b/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/down.sql new file mode 100644 index 0000000000..5aa3a2d278 --- /dev/null +++ b/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts DROP COLUMN maybe_generation_provider; diff --git a/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/up.sql b/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/up.sql new file mode 100644 index 0000000000..35c7ea064f --- /dev/null +++ b/_sql/migrations/2025-07-23-031650_alter_prompts_add_provider/up.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts + ADD COLUMN maybe_generation_provider VARCHAR(16) DEFAULT NULL; diff --git a/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/down.sql b/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/down.sql index d9a93fe9a1..b995da02c2 100644 --- a/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/down.sql +++ b/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/down.sql @@ -1 +1,5 @@ --- This file should undo anything in `up.sql` +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts DROP COLUMN maybe_anonymous_visitor_token; diff --git a/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/up.sql b/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/up.sql index b37f10d95f..749748148f 100644 --- a/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/up.sql +++ b/_sql/migrations/2025-07-23-031720_alter_prompts_add_maybe_anonymous_visitor_token/up.sql @@ -1 +1,6 @@ --- Your SQL goes here +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE prompts + ADD COLUMN maybe_anonymous_visitor_token VARCHAR(32) DEFAULT NULL; diff --git a/_sql/migrations_squashed/prompts.sql b/_sql/migrations_squashed/prompts.sql index 5967b182a1..b7f01e6cff 100644 --- a/_sql/migrations_squashed/prompts.sql +++ b/_sql/migrations_squashed/prompts.sql @@ -19,22 +19,24 @@ CREATE TABLE prompts ( -- Original product to which the prompt applied. -- Prompts may or may not be compatible across products. -- Possible values: - -- * 'stable_diffusion' - -- * 'comfy_ui' + -- * 'stable_diffusion' (legacy) + -- * 'comfy_ui' (legacy) + -- * 'artcraft_app' prompt_type VARCHAR(16) NOT NULL, - -- What service provided the generation. - maybe_generation_provider VARCHAR(16) NOT NULL, - -- What type of model was used to generate the result. -- NB: We're conflating prompts with outputs, but in a -- sense the model is inextricably part of the prompt. maybe_model_type VARCHAR(32) DEFAULT NULL, - -- Whomever created the prompt + -- What service provided the generation. + maybe_generation_provider VARCHAR(16) NOT NULL, + + -- Whoever created the prompt maybe_creator_user_token VARCHAR(32) DEFAULT NULL, - -- TODO: maybe_anonymous_visitor_token VARCHAR(32) DEFAULT NULL, + -- Whoever created the prompt (anonymous user tracking) + maybe_anonymous_visitor_token VARCHAR(32) DEFAULT NULL, -- ========== PROMPT DETAILS ========== diff --git a/crates/schema/public/enums/src/by_table/media_files/media_file_origin_model_type.rs b/crates/schema/public/enums/src/by_table/media_files/media_file_origin_model_type.rs index 97785d24a0..20903fb620 100644 --- a/crates/schema/public/enums/src/by_table/media_files/media_file_origin_model_type.rs +++ b/crates/schema/public/enums/src/by_table/media_files/media_file_origin_model_type.rs @@ -259,7 +259,8 @@ mod tests { #[test] fn serialized_length_ok_for_database() { - const MAX_LENGTH : usize = 32; + // NB: The media_files table has allocated width for VARCHAR(32), but let's slim it down to 24. + const MAX_LENGTH : usize = 24; for variant in MediaFileOriginModelType::all_variants() { let serialized = variant.to_str(); assert!(serialized.len() > 0, "variant {:?} is too short", variant); diff --git a/crates/schema/public/enums/src/common/generation_provider.rs b/crates/schema/public/enums/src/common/generation_provider.rs index e68dcdbc80..dfbe54d729 100644 --- a/crates/schema/public/enums/src/common/generation_provider.rs +++ b/crates/schema/public/enums/src/common/generation_provider.rs @@ -6,6 +6,8 @@ use strum::EnumCount; use strum::EnumIter; use utoipa::ToSchema; +/// NB: This will be used by a variety of tables (MySQL and sqlite)! +/// Keep the max length to 16 characters. #[cfg_attr(test, derive(EnumIter, EnumCount))] #[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "snake_case")] diff --git a/crates/schema/public/enums/src/common/mod.rs b/crates/schema/public/enums/src/common/mod.rs index 0faef0e279..d7ca9ac06b 100644 --- a/crates/schema/public/enums/src/common/mod.rs +++ b/crates/schema/public/enums/src/common/mod.rs @@ -1,6 +1,7 @@ pub mod generation_provider; pub mod job_status; pub mod job_status_plus; +pub mod model_type; pub mod sqlite; pub mod view_as; pub mod visibility; diff --git a/crates/schema/public/enums/src/common/model_type.rs b/crates/schema/public/enums/src/common/model_type.rs new file mode 100644 index 0000000000..3569b49100 --- /dev/null +++ b/crates/schema/public/enums/src/common/model_type.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeSet; + +#[cfg(test)] +use strum::EnumCount; +#[cfg(test)] +use strum::EnumIter; +use utoipa::ToSchema; + +/// NB: This will be used by a variety of tables (MySQL and sqlite)! +/// Keep the max length to 24 characters. +#[cfg_attr(test, derive(EnumIter, EnumCount))] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum ModelType { + Artcraft, + Fal, + Sora, +} + +impl_enum_display_and_debug_using_to_str!(ModelType); +impl_mysql_enum_coders!(ModelType); +impl_mysql_from_row!(ModelType); + +// NB: We can derive `sqlx::Type` instead of using `impl_mysql_enum_coders` + +impl ModelType { + pub fn to_str(&self) -> &'static str { + match self { + Self::Artcraft => "artcraft", + Self::Fal => "fal", + Self::Sora => "sora", + } + } + + pub fn from_str(job_status: &str) -> Result { + match job_status { + "artcraft" => Ok(Self::Artcraft), + "fal" => Ok(Self::Fal), + "sora" => Ok(Self::Sora), + _ => Err(format!("invalid task_state: {:?}", job_status)), + } + } + + pub fn all_variants() -> BTreeSet { + // NB: BTreeSet is sorted + // NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc. + BTreeSet::from([ + Self::Artcraft, + Self::Fal, + Self::Sora, + ]) + } +} + +#[cfg(test)] +mod tests { + use crate::common::model_type::ModelType; + use crate::test_helpers::assert_serialization; + + mod explicit_checks { + use super::*; + + #[test] + fn test_serialization() { + assert_serialization(ModelType::Artcraft, "artcraft"); + assert_serialization(ModelType::Fal, "fal"); + assert_serialization(ModelType::Sora, "sora"); + } + + #[test] + fn to_str() { + assert_eq!(ModelType::Artcraft.to_str(), "artcraft"); + assert_eq!(ModelType::Fal.to_str(), "fal"); + assert_eq!(ModelType::Sora.to_str(), "sora"); + } + + #[test] + fn from_str() { + assert_eq!(ModelType::from_str("artcraft").unwrap(), ModelType::Artcraft); + assert_eq!(ModelType::from_str("fal").unwrap(), ModelType::Fal); + assert_eq!(ModelType::from_str("sora").unwrap(), ModelType::Sora); + } + + #[test] + fn all_variants() { + let mut variants = ModelType::all_variants(); + assert_eq!(variants.len(), 3); + assert_eq!(variants.pop_first(), Some(ModelType::Artcraft)); + assert_eq!(variants.pop_first(), Some(ModelType::Fal)); + assert_eq!(variants.pop_first(), Some(ModelType::Sora)); + assert_eq!(variants.pop_first(), None); + } + } + + mod mechanical_checks { + use super::*; + + #[test] + fn variant_length() { + use strum::IntoEnumIterator; + assert_eq!(ModelType::all_variants().len(), ModelType::iter().len()); + } + + #[test] + fn round_trip() { + for variant in ModelType::all_variants() { + // Test to_str(), from_str(), Display, and Debug. + assert_eq!(variant, ModelType::from_str(variant.to_str()).unwrap()); + assert_eq!(variant, ModelType::from_str(&format!("{}", variant)).unwrap()); + assert_eq!(variant, ModelType::from_str(&format!("{:?}", variant)).unwrap()); + } + } + + #[test] + fn serialized_length_ok_for_database() { + const MAX_LENGTH : usize = 24; + for variant in ModelType::all_variants() { + let serialized = variant.to_str(); + assert!(serialized.len() > 0, "variant {:?} is too short", variant); + assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant); + } + } + } +}