mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
git rid of enums/by_table
This commit is contained in:
1 parent
c9be9bf744
commit
cff0624ffc
89 files changed
+8
-7736
No files matched your search
Generated
+1
@@ -3794,6 +3794,7 @@ dependencies = [
|
||||
name = "enums"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"enums_db",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
||||
@@ -24,7 +24,7 @@ database = ["sqlx", "sqlx-core", "sqlx-mysql"]
|
||||
workspace-build-acceleration.workspace = true
|
||||
|
||||
# Internal
|
||||
# (None yet)
|
||||
enums_db.workspace = true
|
||||
|
||||
# Serialization
|
||||
serde.workspace = true
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use crate::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums_db::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// A forward-compatible version of `FrontendFailureCategory` for API clients.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
use crate::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums_db::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// A restricted subset of `FrontendFailureCategory` that only includes values
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `audit_logs` table in a `VARCHAR(32)` field named `entity_action`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum AuditLogEntityAction {
|
||||
/// Create action
|
||||
#[serde(rename = "create")]
|
||||
Create,
|
||||
|
||||
/// Edit action
|
||||
#[serde(rename = "edit")]
|
||||
Edit,
|
||||
|
||||
/// Edit features (eg. user feature flags)
|
||||
#[serde(rename = "edit_features")]
|
||||
EditFeatures,
|
||||
|
||||
/// Delete action
|
||||
#[serde(rename = "delete")]
|
||||
Delete,
|
||||
|
||||
/// Create featured item
|
||||
#[serde(rename = "featured_item_create")]
|
||||
FeaturedItemCreate,
|
||||
|
||||
/// Delete featured item
|
||||
#[serde(rename = "featured_item_delete")]
|
||||
FeaturedItemDelete,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(AuditLogEntityAction);
|
||||
impl_mysql_enum_coders!(AuditLogEntityAction);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl AuditLogEntityAction {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Create => "create",
|
||||
Self::Edit => "edit",
|
||||
Self::EditFeatures => "edit_features",
|
||||
Self::Delete => "delete",
|
||||
Self::FeaturedItemCreate => "featured_item_create",
|
||||
Self::FeaturedItemDelete => "featured_item_delete",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"create" => Ok(Self::Create),
|
||||
"edit" => Ok(Self::Edit),
|
||||
"edit_features" => Ok(Self::EditFeatures),
|
||||
"delete" => Ok(Self::Delete),
|
||||
"featured_item_create" => Ok(Self::FeaturedItemCreate),
|
||||
"featured_item_delete" => Ok(Self::FeaturedItemDelete),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::audit_logs::audit_log_entity_action::AuditLogEntityAction;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(AuditLogEntityAction::Create, "create");
|
||||
assert_serialization(AuditLogEntityAction::Edit, "edit");
|
||||
assert_serialization(AuditLogEntityAction::EditFeatures, "edit_features");
|
||||
assert_serialization(AuditLogEntityAction::Delete, "delete");
|
||||
assert_serialization(AuditLogEntityAction::FeaturedItemCreate, "featured_item_create");
|
||||
assert_serialization(AuditLogEntityAction::FeaturedItemDelete, "featured_item_delete");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(AuditLogEntityAction::Create.to_str(), "create");
|
||||
assert_eq!(AuditLogEntityAction::Edit.to_str(), "edit");
|
||||
assert_eq!(AuditLogEntityAction::EditFeatures.to_str(), "edit_features");
|
||||
assert_eq!(AuditLogEntityAction::Delete.to_str(), "delete");
|
||||
assert_eq!(AuditLogEntityAction::FeaturedItemCreate.to_str(), "featured_item_create");
|
||||
assert_eq!(AuditLogEntityAction::FeaturedItemDelete.to_str(), "featured_item_delete");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(AuditLogEntityAction::from_str("create").unwrap(), AuditLogEntityAction::Create);
|
||||
assert_eq!(AuditLogEntityAction::from_str("edit").unwrap(), AuditLogEntityAction::Edit);
|
||||
assert_eq!(AuditLogEntityAction::from_str("edit_features").unwrap(), AuditLogEntityAction::EditFeatures);
|
||||
assert_eq!(AuditLogEntityAction::from_str("delete").unwrap(), AuditLogEntityAction::Delete);
|
||||
assert_eq!(AuditLogEntityAction::from_str("featured_item_create").unwrap(), AuditLogEntityAction::FeaturedItemCreate);
|
||||
assert_eq!(AuditLogEntityAction::from_str("featured_item_delete").unwrap(), AuditLogEntityAction::FeaturedItemDelete);
|
||||
assert!(AuditLogEntityAction::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `audit_logs` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum AuditLogEntityType {
|
||||
/// Comment system
|
||||
#[serde(rename = "comment")]
|
||||
Comment,
|
||||
|
||||
/// Media file
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// Model weight
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(AuditLogEntityType);
|
||||
impl_mysql_enum_coders!(AuditLogEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl AuditLogEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Comment => "comment",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::User => "user",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"comment" => Ok(Self::Comment),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"user" => Ok(Self::User),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::audit_logs::audit_log_entity_type::AuditLogEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(AuditLogEntityType::Comment, "comment");
|
||||
assert_serialization(AuditLogEntityType::MediaFile, "media_file");
|
||||
assert_serialization(AuditLogEntityType::ModelWeight, "model_weight");
|
||||
assert_serialization(AuditLogEntityType::User, "user");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(AuditLogEntityType::Comment.to_str(), "comment");
|
||||
assert_eq!(AuditLogEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(AuditLogEntityType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(AuditLogEntityType::User.to_str(), "user");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(AuditLogEntityType::from_str("comment").unwrap(), AuditLogEntityType::Comment);
|
||||
assert_eq!(AuditLogEntityType::from_str("media_file").unwrap(), AuditLogEntityType::MediaFile);
|
||||
assert_eq!(AuditLogEntityType::from_str("model_weight").unwrap(), AuditLogEntityType::ModelWeight);
|
||||
assert_eq!(AuditLogEntityType::from_str("user").unwrap(), AuditLogEntityType::User);
|
||||
assert!(AuditLogEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod audit_log_entity_action;
|
||||
pub mod audit_log_entity_type;
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `batch_generations` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, Ord, PartialOrd, ToSchema)]
|
||||
pub enum BatchGenerationEntityType {
|
||||
/// Media files
|
||||
/// This will probably be the only type supported, but we'll leave the possibility of future types.
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(BatchGenerationEntityType);
|
||||
impl_mysql_enum_coders!(BatchGenerationEntityType);
|
||||
impl_mysql_from_row!(BatchGenerationEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl BatchGenerationEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::MediaFile,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::batch_generations::batch_generation_entity_type::BatchGenerationEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(BatchGenerationEntityType::MediaFile, "media_file");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(BatchGenerationEntityType::MediaFile.to_str(), "media_file");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(BatchGenerationEntityType::from_str("media_file").unwrap(), BatchGenerationEntityType::MediaFile);
|
||||
assert!(BatchGenerationEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = BatchGenerationEntityType::all_variants();
|
||||
assert_eq!(variants.len(), 1);
|
||||
assert_eq!(variants.pop_first(), Some(BatchGenerationEntityType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(BatchGenerationEntityType::all_variants().len(), BatchGenerationEntityType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in BatchGenerationEntityType::all_variants() {
|
||||
assert_eq!(variant, BatchGenerationEntityType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, BatchGenerationEntityType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, BatchGenerationEntityType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod batch_generation_entity_type;
|
||||
@@ -1,109 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `batch_generations` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, Ord, PartialOrd, ToSchema)]
|
||||
pub enum BetaKeyProduct {
|
||||
/// Media files
|
||||
/// This will probably be the only type supported, but we'll leave the possibility of future types.
|
||||
#[serde(rename = "studio")]
|
||||
Studio,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(BetaKeyProduct);
|
||||
impl_mysql_enum_coders!(BetaKeyProduct);
|
||||
impl_mysql_from_row!(BetaKeyProduct);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl BetaKeyProduct {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Studio => "studio",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"studio" => Ok(Self::Studio),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Studio,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::beta_keys::beta_key_product::BetaKeyProduct;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(BetaKeyProduct::Studio, "studio");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(BetaKeyProduct::Studio.to_str(), "studio");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(BetaKeyProduct::from_str("studio").unwrap(), BetaKeyProduct::Studio);
|
||||
assert!(BetaKeyProduct::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = BetaKeyProduct::all_variants();
|
||||
assert_eq!(variants.len(), 1);
|
||||
assert_eq!(variants.pop_first(), Some(BetaKeyProduct::Studio));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(BetaKeyProduct::all_variants().len(), BetaKeyProduct::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in BetaKeyProduct::all_variants() {
|
||||
assert_eq!(variant, BetaKeyProduct::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, BetaKeyProduct::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, BetaKeyProduct::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod beta_key_product;
|
||||
@@ -1,120 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `comments` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)]
|
||||
pub enum CommentEntityType {
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
|
||||
/// Media files
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// Model weights
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
|
||||
/// TTS model (architecture does not matter)
|
||||
#[serde(rename = "tts_model")]
|
||||
TtsModel,
|
||||
|
||||
/// TTS result (architecture does not matter)
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// W2L template
|
||||
#[serde(rename = "w2l_template")]
|
||||
W2lTemplate,
|
||||
|
||||
/// W2L result
|
||||
#[serde(rename = "w2l_result")]
|
||||
W2lResult,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(CommentEntityType);
|
||||
impl_mysql_enum_coders!(CommentEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl CommentEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::User => "user",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::TtsModel => "tts_model",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::W2lTemplate => "w2l_template",
|
||||
Self::W2lResult => "w2l_result",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"user" => Ok(Self::User),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"tts_model" => Ok(Self::TtsModel),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"w2l_template" => Ok(Self::W2lTemplate),
|
||||
"w2l_result" => Ok(Self::W2lResult),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::comments::comment_entity_type::CommentEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(CommentEntityType::User, "user");
|
||||
assert_serialization(CommentEntityType::MediaFile, "media_file");
|
||||
assert_serialization(CommentEntityType::ModelWeight, "model_weight");
|
||||
assert_serialization(CommentEntityType::TtsModel, "tts_model");
|
||||
assert_serialization(CommentEntityType::TtsResult, "tts_result");
|
||||
assert_serialization(CommentEntityType::W2lTemplate, "w2l_template");
|
||||
assert_serialization(CommentEntityType::W2lResult, "w2l_result");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(CommentEntityType::User.to_str(), "user");
|
||||
assert_eq!(CommentEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(CommentEntityType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(CommentEntityType::TtsModel.to_str(), "tts_model");
|
||||
assert_eq!(CommentEntityType::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(CommentEntityType::W2lTemplate.to_str(), "w2l_template");
|
||||
assert_eq!(CommentEntityType::W2lResult.to_str(), "w2l_result");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(CommentEntityType::from_str("user").unwrap(), CommentEntityType::User);
|
||||
assert_eq!(CommentEntityType::from_str("media_file").unwrap(), CommentEntityType::MediaFile);
|
||||
assert_eq!(CommentEntityType::from_str("model_weight").unwrap(), CommentEntityType::ModelWeight);
|
||||
assert_eq!(CommentEntityType::from_str("tts_model").unwrap(), CommentEntityType::TtsModel);
|
||||
assert_eq!(CommentEntityType::from_str("tts_result").unwrap(), CommentEntityType::TtsResult);
|
||||
assert_eq!(CommentEntityType::from_str("w2l_template").unwrap(), CommentEntityType::W2lTemplate);
|
||||
assert_eq!(CommentEntityType::from_str("w2l_result").unwrap(), CommentEntityType::W2lResult);
|
||||
assert!(CommentEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod comment_entity_type;
|
||||
@@ -1,115 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `email_sender_jobs` table in `VARCHAR(32)` field `id_category`.
|
||||
///
|
||||
/// This denotes the type of email being sent.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum EmailCategory {
|
||||
/// User is recently registered
|
||||
#[serde(rename = "welcome")]
|
||||
Welcome,
|
||||
|
||||
/// User is resetting their password
|
||||
#[serde(rename = "password_reset")]
|
||||
PasswordReset,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(EmailCategory);
|
||||
impl_mysql_enum_coders!(EmailCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl EmailCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Welcome => "welcome",
|
||||
Self::PasswordReset => "password_reset",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"welcome" => Ok(Self::Welcome),
|
||||
"password_reset" => Ok(Self::PasswordReset),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Welcome,
|
||||
Self::PasswordReset,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::email_sender_jobs::email_category::EmailCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(EmailCategory::Welcome, "welcome");
|
||||
assert_serialization(EmailCategory::PasswordReset, "password_reset");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(EmailCategory::Welcome.to_str(), "welcome");
|
||||
assert_eq!(EmailCategory::PasswordReset.to_str(), "password_reset");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(EmailCategory::from_str("welcome").unwrap(), EmailCategory::Welcome);
|
||||
assert_eq!(EmailCategory::from_str("password_reset").unwrap(), EmailCategory::PasswordReset);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = EmailCategory::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert_eq!(variants.pop_first(), Some(EmailCategory::Welcome));
|
||||
assert_eq!(variants.pop_first(), Some(EmailCategory::PasswordReset));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(EmailCategory::all_variants().len(), EmailCategory::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(EmailCategory::all_variants().len(), EmailCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in EmailCategory::all_variants() {
|
||||
assert_eq!(variant, EmailCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, EmailCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, EmailCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod email_category;
|
||||
@@ -1 +0,0 @@
|
||||
pub mod stats_entity_type;
|
||||
@@ -1,122 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `user_stats` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema, Ord, PartialOrd)]
|
||||
pub enum StatsEntityType {
|
||||
/// Comment
|
||||
#[serde(rename = "comment")]
|
||||
Comment,
|
||||
|
||||
/// MediaFile
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// ModelWeight (the new way to store models)
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(StatsEntityType);
|
||||
impl_mysql_enum_coders!(StatsEntityType);
|
||||
impl_mysql_from_row!(StatsEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl StatsEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Comment => "comment",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"comment" => Ok(Self::Comment),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Comment,
|
||||
Self::MediaFile,
|
||||
Self::ModelWeight,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::entity_stats::stats_entity_type::StatsEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(StatsEntityType::Comment, "comment");
|
||||
assert_serialization(StatsEntityType::MediaFile, "media_file");
|
||||
assert_serialization(StatsEntityType::ModelWeight, "model_weight");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(StatsEntityType::Comment.to_str(), "comment");
|
||||
assert_eq!(StatsEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(StatsEntityType::ModelWeight.to_str(), "model_weight");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(StatsEntityType::from_str("comment").unwrap(), StatsEntityType::Comment);
|
||||
assert_eq!(StatsEntityType::from_str("media_file").unwrap(), StatsEntityType::MediaFile);
|
||||
assert_eq!(StatsEntityType::from_str("model_weight").unwrap(), StatsEntityType::ModelWeight);
|
||||
assert!(StatsEntityType::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = StatsEntityType::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert_eq!(variants.pop_first(), Some(StatsEntityType::Comment));
|
||||
assert_eq!(variants.pop_first(), Some(StatsEntityType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(StatsEntityType::ModelWeight));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(StatsEntityType::all_variants().len(), StatsEntityType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in StatsEntityType::all_variants() {
|
||||
assert_eq!(variant, StatsEntityType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, StatsEntityType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, StatsEntityType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum FeaturedItemEntityType {
|
||||
/// MediaFile
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// ModelWeight (the new way to store models)
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(FeaturedItemEntityType);
|
||||
impl_mysql_enum_coders!(FeaturedItemEntityType);
|
||||
impl_mysql_from_row!(FeaturedItemEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl FeaturedItemEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::User => "user",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"user" => Ok(Self::User),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::MediaFile,
|
||||
Self::ModelWeight,
|
||||
Self::User,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::featured_items::featured_item_entity_type::FeaturedItemEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(FeaturedItemEntityType::MediaFile, "media_file");
|
||||
assert_serialization(FeaturedItemEntityType::ModelWeight, "model_weight");
|
||||
assert_serialization(FeaturedItemEntityType::User, "user");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(FeaturedItemEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(FeaturedItemEntityType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(FeaturedItemEntityType::User.to_str(), "user");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(FeaturedItemEntityType::from_str("media_file").unwrap(), FeaturedItemEntityType::MediaFile);
|
||||
assert_eq!(FeaturedItemEntityType::from_str("model_weight").unwrap(), FeaturedItemEntityType::ModelWeight);
|
||||
assert_eq!(FeaturedItemEntityType::from_str("user").unwrap(), FeaturedItemEntityType::User);
|
||||
assert!(FeaturedItemEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(FeaturedItemEntityType::all_variants().len(), FeaturedItemEntityType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in FeaturedItemEntityType::all_variants() {
|
||||
assert_eq!(variant, FeaturedItemEntityType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, FeaturedItemEntityType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, FeaturedItemEntityType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in FeaturedItemEntityType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod featured_item_entity_type;
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
// TODO: Use macro-derived impls
|
||||
|
||||
/// Our "generic downloads" pipeline supports a wide variety of ML models and other media.
|
||||
/// They are serialized in the database table `generic_download_jobs` as a VARCHAR(32).
|
||||
///
|
||||
/// Each type of download is identified by the following enum variants.
|
||||
/// These types are present in the HTTP API and database columns as serialized here.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize, Hash, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "database", derive(sqlx::Type))]
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
pub enum GenericDownloadType {
|
||||
/// NB: Note - this is hifigan for Tacotron2.
|
||||
/// Some work will be needed to unify this with other hifigan types.
|
||||
#[serde(rename = "hifigan")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "hifigan"))]
|
||||
HifiGan,
|
||||
|
||||
/// NB: Note - this is hifigan for SoftVC (our internal codename is "rocketvc").
|
||||
/// Some work will need to be done to unify this with other hifigan types.
|
||||
#[serde(rename = "hifigan_rocket_vc")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "hifigan_rocket_vc"))]
|
||||
HifiGanRocketVc,
|
||||
|
||||
/// NB: Note - this is hifigan for SoVitsSvc
|
||||
/// Some work will need to be done to unify this with other hifigan types.
|
||||
#[serde(rename = "hifigan_so_vits_svc")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "hifigan_so_vits_svc"))]
|
||||
HifiGanSoVitsSvc,
|
||||
|
||||
//#[serde(rename = "melgan_vocodes")]
|
||||
//#[sqlx(rename = "melgan_vocodes")]
|
||||
//MelGanVocodes,
|
||||
|
||||
/// NB: Our external-facing name for "softvc" is rocketvc.
|
||||
/// I wish we could stop being stupid about this.
|
||||
#[serde(rename = "rocket_vc")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "rocket_vc"))]
|
||||
RocketVc,
|
||||
|
||||
/// RVC (v2) voice conversion models
|
||||
#[serde(rename = "rvc_v2")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "rvc_v2"))]
|
||||
RvcV2,
|
||||
|
||||
/// so-vits-svc voice conversion models
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "so_vits_svc"))]
|
||||
SoVitsSvc,
|
||||
|
||||
/// Tacotron TTS models.
|
||||
#[serde(rename = "tacotron2")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "tacotron2"))]
|
||||
Tacotron2,
|
||||
|
||||
/// VITS TTS models.
|
||||
#[serde(rename = "vits")]
|
||||
#[cfg_attr(feature = "database", sqlx(rename = "vits"))]
|
||||
Vits,
|
||||
}
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl GenericDownloadType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::HifiGan => "hifigan",
|
||||
Self::HifiGanRocketVc => "hifigan_rocket_vc",
|
||||
Self::HifiGanSoVitsSvc => "hifigan_so_vits_svc",
|
||||
Self::RocketVc => "rocket_vc",
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
Self::Tacotron2 => "tacotron2",
|
||||
Self::Vits => "vits",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"hifigan" => Ok(Self::HifiGan),
|
||||
"hifigan_rocket_vc" => Ok(Self::HifiGanRocketVc),
|
||||
"hifigan_so_vits_svc" => Ok(Self::HifiGanSoVitsSvc),
|
||||
"rocket_vc" => Ok(Self::RocketVc),
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
"tacotron2" => Ok(Self::Tacotron2),
|
||||
"vits" => Ok(Self::Vits),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::HifiGan,
|
||||
Self::HifiGanRocketVc,
|
||||
Self::HifiGanSoVitsSvc,
|
||||
Self::RocketVc,
|
||||
Self::RvcV2,
|
||||
Self::SoVitsSvc,
|
||||
Self::Tacotron2,
|
||||
Self::Vits,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_download_jobs::generic_download_type::GenericDownloadType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(GenericDownloadType::HifiGan, "hifigan");
|
||||
assert_serialization(GenericDownloadType::HifiGanRocketVc, "hifigan_rocket_vc");
|
||||
assert_serialization(GenericDownloadType::HifiGanSoVitsSvc, "hifigan_so_vits_svc");
|
||||
assert_serialization(GenericDownloadType::RocketVc, "rocket_vc");
|
||||
assert_serialization(GenericDownloadType::RvcV2, "rvc_v2");
|
||||
assert_serialization(GenericDownloadType::SoVitsSvc, "so_vits_svc");
|
||||
assert_serialization(GenericDownloadType::Tacotron2, "tacotron2");
|
||||
assert_serialization(GenericDownloadType::Vits, "vits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(GenericDownloadType::HifiGan.to_str(), "hifigan");
|
||||
assert_eq!(GenericDownloadType::HifiGanRocketVc.to_str(), "hifigan_rocket_vc");
|
||||
assert_eq!(GenericDownloadType::HifiGanSoVitsSvc.to_str(), "hifigan_so_vits_svc");
|
||||
assert_eq!(GenericDownloadType::RocketVc.to_str(), "rocket_vc");
|
||||
assert_eq!(GenericDownloadType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(GenericDownloadType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(GenericDownloadType::Tacotron2.to_str(), "tacotron2");
|
||||
assert_eq!(GenericDownloadType::Vits.to_str(), "vits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(GenericDownloadType::from_str("hifigan").unwrap(), GenericDownloadType::HifiGan);
|
||||
assert_eq!(GenericDownloadType::from_str("hifigan_rocket_vc").unwrap(), GenericDownloadType::HifiGanRocketVc);
|
||||
assert_eq!(GenericDownloadType::from_str("hifigan_so_vits_svc").unwrap(), GenericDownloadType::HifiGanSoVitsSvc);
|
||||
assert_eq!(GenericDownloadType::from_str("rocket_vc").unwrap(), GenericDownloadType::RocketVc);
|
||||
assert_eq!(GenericDownloadType::from_str("rvc_v2").unwrap(), GenericDownloadType::RvcV2);
|
||||
assert_eq!(GenericDownloadType::from_str("so_vits_svc").unwrap(), GenericDownloadType::SoVitsSvc);
|
||||
assert_eq!(GenericDownloadType::from_str("tacotron2").unwrap(), GenericDownloadType::Tacotron2);
|
||||
assert_eq!(GenericDownloadType::from_str("vits").unwrap(), GenericDownloadType::Vits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = GenericDownloadType::all_variants();
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::HifiGan));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::HifiGanRocketVc));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::HifiGanSoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::RocketVc));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::SoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::Tacotron2));
|
||||
assert_eq!(variants.pop_first(), Some(GenericDownloadType::Vits));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(GenericDownloadType::all_variants().len(), GenericDownloadType::iter().len());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod generic_download_type;
|
||||
-265
@@ -1,265 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `frontend_failure_category`.
|
||||
///
|
||||
/// When jobs fail (permanently or transiently), we need to inform the frontend of the reason,
|
||||
/// because perhaps there's something the user can do to change their input.
|
||||
///
|
||||
/// The previous "VARCHAR(32) failure_reason" column was a text-based message that could not be
|
||||
/// localized or made user friendly. This `frontend_failure_category` exists to provide well-defined
|
||||
/// failure categories to the frontend that can easily be localized and indicated consistently in
|
||||
/// the UI.
|
||||
///
|
||||
/// Another benefit is that we'll surface all of the various types of failure and perhaps eventually
|
||||
/// come to handle some in a cross-cutting way.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum FrontendFailureCategory {
|
||||
/// When a face is not detected in the image used for animation.
|
||||
/// For SadTalker (and possibly Wav2Lip)
|
||||
#[serde(rename = "face_not_detected")]
|
||||
FaceNotDetected,
|
||||
|
||||
/// The user stepped away from their device and expected the workload to finish.
|
||||
/// Some workloads require that the user keep their browser open.
|
||||
#[serde(rename = "keep_alive_elapsed")]
|
||||
KeepAliveElapsed,
|
||||
|
||||
/// This is mostly for developers -- a feature isn't complete somewhere in the code.
|
||||
/// Big oops if errors of this class make it to production.
|
||||
#[serde(rename = "not_yet_implemented")]
|
||||
NotYetImplemented,
|
||||
|
||||
/// Tell the user that some kind of transient error happened. They don't need to know
|
||||
/// exactly what happened. We'll retry their workload in any case.
|
||||
#[serde(rename = "retryable_worker_error")]
|
||||
RetryableWorkerError,
|
||||
|
||||
/// Model content rules were violated
|
||||
/// Eg. Seedance 2 will report: "your input text violates platform rules. please modify and try again"
|
||||
#[serde(rename = "model_rules_violation")]
|
||||
ModelRulesViolation,
|
||||
|
||||
/// Model content violation
|
||||
/// e.g. "Your uploaded image violates platform rules. Please modify and try again." (seedance2pro)
|
||||
/// Model content rules prohibit the uploaded image.
|
||||
#[serde(rename = "rule_bans_user_image")]
|
||||
RuleBansUserImage,
|
||||
|
||||
/// Model content violation
|
||||
/// Model content rules prohibit user uploaded images containing faces (Seedance 2.0)
|
||||
/// e.g. "The generated video did not pass review. Credits will not be deducted." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_user_image_with_faces")]
|
||||
RuleBansUserImageWithFaces,
|
||||
|
||||
/// Model content violation
|
||||
/// Model content rules prohibit the user's given text prompt (this fails early).
|
||||
/// e.g. "The generated video did not pass review. Credits will not be deducted." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_user_text_prompt")]
|
||||
RuleBansUserTextPrompt,
|
||||
|
||||
/// Model content violation
|
||||
/// Model content rules prohibit user content. (I think this check happens early.)
|
||||
/// e.g. "Content violates platform rules. Please modify and try again." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_user_content")]
|
||||
RuleBansUserContent,
|
||||
|
||||
/// Model content violation
|
||||
/// The video didn't pass checks after it finished generation (this fails at the very end of the generation).
|
||||
/// e.g. "The generated video did not pass review. Credits will not be deducted." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_generated_video")]
|
||||
RuleBansGeneratedVideo,
|
||||
|
||||
/// Model content violation
|
||||
/// The audio (even in video!) didn't pass checks after it finished generation (this fails at the very end of the generation).
|
||||
/// e.g. "The generated audio violates platform rules. Please adjust your prompt or images and try again." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_generated_audio")]
|
||||
RuleBansGeneratedAudio,
|
||||
|
||||
/// Model content violation
|
||||
/// The content didn't pass checks after it finished generation (this fails at the very end of the generation).
|
||||
/// e.g. "The generated content violates platform rules. Please adjust your prompt or images and try again." (seedance2pro)
|
||||
#[serde(rename = "rule_bans_generated_content")]
|
||||
RuleBansGeneratedContent,
|
||||
|
||||
/// Generation failed (no reason)
|
||||
/// Unspecified failure reason
|
||||
/// Various example failures:
|
||||
/// - "The generated video did not pass review. Credits will not be deducted." (seedance2pro)
|
||||
/// - "Server error. Please try again later." (seedance2pro)
|
||||
#[serde(rename = "generation_failed")]
|
||||
GenerationFailed,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(FrontendFailureCategory);
|
||||
impl_mysql_enum_coders!(FrontendFailureCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl FrontendFailureCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::FaceNotDetected => "face_not_detected",
|
||||
Self::KeepAliveElapsed => "keep_alive_elapsed",
|
||||
Self::NotYetImplemented => "not_yet_implemented",
|
||||
Self::RetryableWorkerError => "retryable_worker_error",
|
||||
Self::ModelRulesViolation => "model_rules_violation",
|
||||
Self::RuleBansUserImage => "rule_bans_user_image",
|
||||
Self::RuleBansUserImageWithFaces => "rule_bans_user_image_with_faces",
|
||||
Self::RuleBansUserTextPrompt => "rule_bans_user_text_prompt",
|
||||
Self::RuleBansUserContent => "rule_bans_user_content",
|
||||
Self::RuleBansGeneratedVideo => "rule_bans_generated_video",
|
||||
Self::RuleBansGeneratedAudio => "rule_bans_generated_audio",
|
||||
Self::RuleBansGeneratedContent => "rule_bans_generated_content",
|
||||
Self::GenerationFailed => "generation_failed",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"face_not_detected" => Ok(Self::FaceNotDetected),
|
||||
"keep_alive_elapsed" => Ok(Self::KeepAliveElapsed),
|
||||
"not_yet_implemented" => Ok(Self::NotYetImplemented),
|
||||
"retryable_worker_error" => Ok(Self::RetryableWorkerError),
|
||||
"model_rules_violation" => Ok(Self::ModelRulesViolation),
|
||||
"rule_bans_user_image" => Ok(Self::RuleBansUserImage),
|
||||
"rule_bans_user_image_with_faces" => Ok(Self::RuleBansUserImageWithFaces),
|
||||
"rule_bans_user_text_prompt" => Ok(Self::RuleBansUserTextPrompt),
|
||||
"rule_bans_user_content" => Ok(Self::RuleBansUserContent),
|
||||
"rule_bans_generated_video" => Ok(Self::RuleBansGeneratedVideo),
|
||||
"rule_bans_generated_audio" => Ok(Self::RuleBansGeneratedAudio),
|
||||
"rule_bans_generated_content" => Ok(Self::RuleBansGeneratedContent),
|
||||
"generation_failed" => Ok(Self::GenerationFailed),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::FaceNotDetected,
|
||||
Self::KeepAliveElapsed,
|
||||
Self::NotYetImplemented,
|
||||
Self::RetryableWorkerError,
|
||||
Self::ModelRulesViolation,
|
||||
Self::RuleBansUserImage,
|
||||
Self::RuleBansUserImageWithFaces,
|
||||
Self::RuleBansUserTextPrompt,
|
||||
Self::RuleBansUserContent,
|
||||
Self::RuleBansGeneratedVideo,
|
||||
Self::RuleBansGeneratedAudio,
|
||||
Self::RuleBansGeneratedContent,
|
||||
Self::GenerationFailed,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(FrontendFailureCategory::FaceNotDetected, "face_not_detected");
|
||||
assert_serialization(FrontendFailureCategory::KeepAliveElapsed, "keep_alive_elapsed");
|
||||
assert_serialization(FrontendFailureCategory::NotYetImplemented, "not_yet_implemented");
|
||||
assert_serialization(FrontendFailureCategory::RetryableWorkerError, "retryable_worker_error");
|
||||
assert_serialization(FrontendFailureCategory::ModelRulesViolation, "model_rules_violation");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansUserImage, "rule_bans_user_image");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansUserImageWithFaces, "rule_bans_user_image_with_faces");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansUserTextPrompt, "rule_bans_user_text_prompt");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansUserContent, "rule_bans_user_content");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansGeneratedVideo, "rule_bans_generated_video");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansGeneratedAudio, "rule_bans_generated_audio");
|
||||
assert_serialization(FrontendFailureCategory::RuleBansGeneratedContent, "rule_bans_generated_content");
|
||||
assert_serialization(FrontendFailureCategory::GenerationFailed, "generation_failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(FrontendFailureCategory::FaceNotDetected.to_str(), "face_not_detected");
|
||||
assert_eq!(FrontendFailureCategory::KeepAliveElapsed.to_str(), "keep_alive_elapsed");
|
||||
assert_eq!(FrontendFailureCategory::NotYetImplemented.to_str(), "not_yet_implemented");
|
||||
assert_eq!(FrontendFailureCategory::RetryableWorkerError.to_str(), "retryable_worker_error");
|
||||
assert_eq!(FrontendFailureCategory::ModelRulesViolation.to_str(), "model_rules_violation");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansUserImage.to_str(), "rule_bans_user_image");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansUserImageWithFaces.to_str(), "rule_bans_user_image_with_faces");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansUserTextPrompt.to_str(), "rule_bans_user_text_prompt");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansUserContent.to_str(), "rule_bans_user_content");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansGeneratedVideo.to_str(), "rule_bans_generated_video");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansGeneratedAudio.to_str(), "rule_bans_generated_audio");
|
||||
assert_eq!(FrontendFailureCategory::RuleBansGeneratedContent.to_str(), "rule_bans_generated_content");
|
||||
assert_eq!(FrontendFailureCategory::GenerationFailed.to_str(), "generation_failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(FrontendFailureCategory::from_str("face_not_detected").unwrap(), FrontendFailureCategory::FaceNotDetected);
|
||||
assert_eq!(FrontendFailureCategory::from_str("keep_alive_elapsed").unwrap(), FrontendFailureCategory::KeepAliveElapsed);
|
||||
assert_eq!(FrontendFailureCategory::from_str("not_yet_implemented").unwrap(), FrontendFailureCategory::NotYetImplemented);
|
||||
assert_eq!(FrontendFailureCategory::from_str("retryable_worker_error").unwrap(), FrontendFailureCategory::RetryableWorkerError);
|
||||
assert_eq!(FrontendFailureCategory::from_str("model_rules_violation").unwrap(), FrontendFailureCategory::ModelRulesViolation);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_user_image").unwrap(), FrontendFailureCategory::RuleBansUserImage);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_user_image_with_faces").unwrap(), FrontendFailureCategory::RuleBansUserImageWithFaces);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_user_text_prompt").unwrap(), FrontendFailureCategory::RuleBansUserTextPrompt);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_user_content").unwrap(), FrontendFailureCategory::RuleBansUserContent);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_video").unwrap(), FrontendFailureCategory::RuleBansGeneratedVideo);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_audio").unwrap(), FrontendFailureCategory::RuleBansGeneratedAudio);
|
||||
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_content").unwrap(), FrontendFailureCategory::RuleBansGeneratedContent);
|
||||
assert_eq!(FrontendFailureCategory::from_str("generation_failed").unwrap(), FrontendFailureCategory::GenerationFailed);
|
||||
assert_eq!(FrontendFailureCategory::from_str("invalid_value").is_err(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = FrontendFailureCategory::all_variants();
|
||||
assert_eq!(variants.len(), 13);
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::FaceNotDetected));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::KeepAliveElapsed));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::NotYetImplemented));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RetryableWorkerError));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::ModelRulesViolation));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansUserImage));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansUserImageWithFaces));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansUserTextPrompt));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansUserContent));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedVideo));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedAudio));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedContent));
|
||||
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::GenerationFailed));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(FrontendFailureCategory::all_variants().len(), FrontendFailureCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in FrontendFailureCategory::all_variants() {
|
||||
assert_eq!(variant, FrontendFailureCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, FrontendFailureCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, FrontendFailureCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `inference_category`.
|
||||
///
|
||||
/// Our "generic inference" pipeline supports a wide variety of ML models and other media.
|
||||
/// Each "category" of inference is identified by the following enum variants.
|
||||
/// These types are present in the HTTP API and database columns as serialized here.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default, ToSchema)]
|
||||
pub enum InferenceCategory {
|
||||
/// Deprecate this field !!!
|
||||
/// We should drain all jobs from using this database field, then remove it.
|
||||
#[deprecated(note = "NB(bt,2024-09-05): The frontend still needs this")]
|
||||
#[serde(rename = "deprecated_field")]
|
||||
DeprecatedField,
|
||||
|
||||
/// Facial lipsync animation (eg. SadTalker, Wav2Lip, FaceFusion)
|
||||
#[serde(rename = "lipsync_animation")]
|
||||
#[default]
|
||||
LipsyncAnimation,
|
||||
|
||||
/// FakeYou's text to speech (eg. Tacotron2)
|
||||
#[serde(rename = "text_to_speech")]
|
||||
TextToSpeech,
|
||||
|
||||
/// FakeYou's voice conversion (eg. svc, rvc)
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversion,
|
||||
|
||||
/// Image generation (eg. Stable Diffusion 1.5), FAL-powered image generation, etc.
|
||||
#[serde(rename = "image_generation")]
|
||||
ImageGeneration,
|
||||
|
||||
/// FAL-powered video generation
|
||||
/// (Also Seedance2-Pro.com)
|
||||
#[serde(rename = "video_generation")]
|
||||
VideoGeneration,
|
||||
|
||||
/// FAL-powered 3D object generation
|
||||
#[serde(rename = "object_generation")]
|
||||
ObjectGeneration,
|
||||
|
||||
/// Gaussian Splat generation (eg. World Labs Marble)
|
||||
#[serde(rename = "splat_generation")]
|
||||
SplatGeneration,
|
||||
|
||||
/// FAL-powered image background removal
|
||||
#[serde(rename = "background_removal")]
|
||||
BackgroundRemoval,
|
||||
|
||||
/// Turn video into animation data with mocap processing (eg. Mocapnet).
|
||||
#[serde(rename = "mocap")]
|
||||
Mocap,
|
||||
|
||||
/// ComfyUI workflows
|
||||
/// This is what powers Storyteller Studio!
|
||||
#[serde(rename = "workflow")]
|
||||
Workflow,
|
||||
|
||||
/// FBX to GLTF/GLB.
|
||||
/// Still supported, but few people will use it.
|
||||
#[serde(rename = "format_conversion")]
|
||||
FormatConversion,
|
||||
|
||||
/// Live portrait
|
||||
#[serde(rename = "live_portrait")]
|
||||
LivePortrait,
|
||||
|
||||
#[serde(rename="seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
/// DEPRECATED. Do not use.
|
||||
/// This was for ReRenderAVideo, which we never productionized.
|
||||
#[deprecated(note = "This was for ReRenderAVideo, which we never productionized.")]
|
||||
#[serde(rename = "video_filter")]
|
||||
VideoFilter,
|
||||
|
||||
/// DEPRECATED. Bevy engine serverside rendering.
|
||||
#[deprecated(note = "This was for Bevy engine's server side rendering.")]
|
||||
#[serde(rename = "convert_bvh_to_workflow")]
|
||||
ConvertBvhToWorkflow,
|
||||
|
||||
#[serde(rename = "f5_tts")]
|
||||
F5TTS,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceCategory);
|
||||
impl_mysql_enum_coders!(InferenceCategory);
|
||||
impl_mysql_from_row!(InferenceCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::DeprecatedField => "deprecated_field",
|
||||
Self::LipsyncAnimation => "lipsync_animation",
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::ImageGeneration => "image_generation",
|
||||
Self::VideoGeneration => "video_generation",
|
||||
Self::ObjectGeneration => "object_generation",
|
||||
Self::SplatGeneration => "splat_generation",
|
||||
Self::BackgroundRemoval => "background_removal",
|
||||
Self::Mocap => "mocap",
|
||||
Self::Workflow => "workflow",
|
||||
Self::F5TTS => "f5_tts",
|
||||
Self::FormatConversion => "format_conversion",
|
||||
Self::LivePortrait => "live_portrait",
|
||||
Self::SeedVc => "seed_vc",
|
||||
Self::VideoFilter => "video_filter",
|
||||
Self::ConvertBvhToWorkflow => "convert_bvh_to_workflow",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"deprecated_field" => Ok(Self::DeprecatedField),
|
||||
"lipsync_animation" => Ok(Self::LipsyncAnimation),
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"image_generation" => Ok(Self::ImageGeneration),
|
||||
"video_generation" => Ok(Self::VideoGeneration),
|
||||
"object_generation" => Ok(Self::ObjectGeneration),
|
||||
"splat_generation" => Ok(Self::SplatGeneration),
|
||||
"background_removal" => Ok(Self::BackgroundRemoval),
|
||||
"f5_tts" => Ok(Self::F5TTS),
|
||||
"mocap" => Ok(Self::Mocap),
|
||||
"workflow" => Ok(Self::Workflow),
|
||||
"format_conversion" => Ok(Self::FormatConversion),
|
||||
"live_portrait" => Ok(Self::LivePortrait),
|
||||
"seed_vc" => Ok(Self::SeedVc),
|
||||
"video_filter" => Ok(Self::VideoFilter),
|
||||
"convert_bvh_to_workflow" => Ok(Self::ConvertBvhToWorkflow),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::DeprecatedField,
|
||||
Self::LipsyncAnimation,
|
||||
Self::TextToSpeech,
|
||||
Self::VoiceConversion,
|
||||
Self::ImageGeneration,
|
||||
Self::ObjectGeneration,
|
||||
Self::SplatGeneration,
|
||||
Self::VideoGeneration,
|
||||
Self::BackgroundRemoval,
|
||||
Self::Mocap,
|
||||
Self::F5TTS,
|
||||
Self::SeedVc,
|
||||
Self::Workflow,
|
||||
Self::FormatConversion,
|
||||
Self::LivePortrait,
|
||||
Self::VideoFilter,
|
||||
Self::ConvertBvhToWorkflow,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceCategory::DeprecatedField, "deprecated_field");
|
||||
assert_serialization(InferenceCategory::LipsyncAnimation, "lipsync_animation");
|
||||
assert_serialization(InferenceCategory::TextToSpeech, "text_to_speech");
|
||||
assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(InferenceCategory::ImageGeneration, "image_generation");
|
||||
assert_serialization(InferenceCategory::VideoGeneration, "video_generation");
|
||||
assert_serialization(InferenceCategory::ObjectGeneration, "object_generation");
|
||||
assert_serialization(InferenceCategory::SplatGeneration, "splat_generation");
|
||||
assert_serialization(InferenceCategory::BackgroundRemoval, "background_removal");
|
||||
assert_serialization(InferenceCategory::Mocap, "mocap");
|
||||
assert_serialization(InferenceCategory::F5TTS, "f5_tts");
|
||||
assert_serialization(InferenceCategory::SeedVc, "seed_vc");
|
||||
assert_serialization(InferenceCategory::Workflow, "workflow");
|
||||
assert_serialization(InferenceCategory::FormatConversion, "format_conversion");
|
||||
assert_serialization(InferenceCategory::LivePortrait, "live_portrait");
|
||||
assert_serialization(InferenceCategory::VideoFilter, "video_filter");
|
||||
assert_serialization(InferenceCategory::ConvertBvhToWorkflow, "convert_bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceCategory::DeprecatedField.to_str(), "deprecated_field");
|
||||
assert_eq!(InferenceCategory::LipsyncAnimation.to_str(), "lipsync_animation");
|
||||
assert_eq!(InferenceCategory::TextToSpeech.to_str(), "text_to_speech");
|
||||
assert_eq!(InferenceCategory::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(InferenceCategory::ImageGeneration.to_str(), "image_generation");
|
||||
assert_eq!(InferenceCategory::VideoGeneration.to_str(), "video_generation");
|
||||
assert_eq!(InferenceCategory::ObjectGeneration.to_str(), "object_generation");
|
||||
assert_eq!(InferenceCategory::SplatGeneration.to_str(), "splat_generation");
|
||||
assert_eq!(InferenceCategory::BackgroundRemoval.to_str(), "background_removal");
|
||||
assert_eq!(InferenceCategory::F5TTS.to_str(), "f5_tts");
|
||||
assert_eq!(InferenceCategory::SeedVc.to_str(), "seed_vc");
|
||||
assert_eq!(InferenceCategory::Mocap.to_str(), "mocap");
|
||||
assert_eq!(InferenceCategory::Workflow.to_str(), "workflow");
|
||||
assert_eq!(InferenceCategory::FormatConversion.to_str(), "format_conversion");
|
||||
assert_eq!(InferenceCategory::LivePortrait.to_str(), "live_portrait");
|
||||
assert_eq!(InferenceCategory::VideoFilter.to_str(), "video_filter");
|
||||
assert_eq!(InferenceCategory::ConvertBvhToWorkflow.to_str(), "convert_bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceCategory::from_str("deprecated_field").unwrap(), InferenceCategory::DeprecatedField);
|
||||
assert_eq!(InferenceCategory::from_str("lipsync_animation").unwrap(), InferenceCategory::LipsyncAnimation);
|
||||
assert_eq!(InferenceCategory::from_str("text_to_speech").unwrap(), InferenceCategory::TextToSpeech);
|
||||
assert_eq!(InferenceCategory::from_str("voice_conversion").unwrap(), InferenceCategory::VoiceConversion);
|
||||
assert_eq!(InferenceCategory::from_str("image_generation").unwrap(), InferenceCategory::ImageGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("video_generation").unwrap(), InferenceCategory::VideoGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("object_generation").unwrap(), InferenceCategory::ObjectGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("splat_generation").unwrap(), InferenceCategory::SplatGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("background_removal").unwrap(), InferenceCategory::BackgroundRemoval);
|
||||
assert_eq!(InferenceCategory::from_str("f5_tts").unwrap(), InferenceCategory::F5TTS);
|
||||
assert_eq!(InferenceCategory::from_str("seed_vc").unwrap(), InferenceCategory::SeedVc);
|
||||
assert_eq!(InferenceCategory::from_str("mocap").unwrap(), InferenceCategory::Mocap);
|
||||
assert_eq!(InferenceCategory::from_str("workflow").unwrap(), InferenceCategory::Workflow);
|
||||
assert_eq!(InferenceCategory::from_str("format_conversion").unwrap(), InferenceCategory::FormatConversion);
|
||||
assert_eq!(InferenceCategory::from_str("live_portrait").unwrap(), InferenceCategory::LivePortrait);
|
||||
assert_eq!(InferenceCategory::from_str("video_filter").unwrap(), InferenceCategory::VideoFilter);
|
||||
assert_eq!(InferenceCategory::from_str("convert_bvh_to_workflow").unwrap(), InferenceCategory::ConvertBvhToWorkflow);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
const EXPECTED_COUNT : usize = 17;
|
||||
|
||||
assert_eq!(InferenceCategory::all_variants().len(), EXPECTED_COUNT);
|
||||
assert_eq!(InferenceCategory::iter().len(), EXPECTED_COUNT);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceCategory::all_variants().len(), InferenceCategory::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceCategory::all_variants().len(), InferenceCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in InferenceCategory::all_variants() {
|
||||
assert_eq!(variant, InferenceCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, InferenceCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, InferenceCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in InferenceCategory::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `maybe_input_source_token`.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum InferenceInputSourceTokenType {
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
#[serde(rename = "media_upload")]
|
||||
MediaUpload,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceInputSourceTokenType);
|
||||
impl_mysql_enum_coders!(InferenceInputSourceTokenType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceInputSourceTokenType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::MediaUpload => "media_upload",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"media_upload" => Ok(Self::MediaUpload),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<InferenceInputSourceTokenType> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
InferenceInputSourceTokenType::MediaFile,
|
||||
InferenceInputSourceTokenType::MediaUpload,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_input_source_token_type::InferenceInputSourceTokenType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceInputSourceTokenType::MediaFile, "media_file");
|
||||
assert_serialization(InferenceInputSourceTokenType::MediaUpload, "media_upload");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceInputSourceTokenType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(InferenceInputSourceTokenType::MediaUpload.to_str(), "media_upload");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceInputSourceTokenType::from_str("media_file").unwrap(), InferenceInputSourceTokenType::MediaFile);
|
||||
assert_eq!(InferenceInputSourceTokenType::from_str("media_upload").unwrap(), InferenceInputSourceTokenType::MediaUpload);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceInputSourceTokenType::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceInputSourceTokenType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceInputSourceTokenType::MediaUpload));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceInputSourceTokenType::all_variants().len(), InferenceInputSourceTokenType::iter().len());
|
||||
}
|
||||
}
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(16)` field `maybe_external_third_party`.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InferenceJobExternalThirdParty {
|
||||
/// Fal jobs
|
||||
#[serde(rename = "fal")]
|
||||
#[default]
|
||||
Fal,
|
||||
|
||||
/// Seedance 2 Pro jobs
|
||||
#[serde(rename = "seedance2pro")]
|
||||
Seedance2Pro,
|
||||
|
||||
/// World Labs jobs
|
||||
#[serde(rename = "worldlabs")]
|
||||
Worldlabs,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceJobExternalThirdParty);
|
||||
impl_mysql_enum_coders!(InferenceJobExternalThirdParty);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceJobExternalThirdParty {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Fal => "fal",
|
||||
Self::Seedance2Pro => "seedance2pro",
|
||||
Self::Worldlabs => "worldlabs",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"fal" => Ok(Self::Fal),
|
||||
"seedance2pro" => Ok(Self::Seedance2Pro),
|
||||
"worldlabs" => Ok(Self::Worldlabs),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Fal,
|
||||
Self::Seedance2Pro,
|
||||
Self::Worldlabs,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_job_external_third_party::InferenceJobExternalThirdParty;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceJobExternalThirdParty::Fal, "fal");
|
||||
assert_serialization(InferenceJobExternalThirdParty::Seedance2Pro, "seedance2pro");
|
||||
assert_serialization(InferenceJobExternalThirdParty::Worldlabs, "worldlabs");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceJobExternalThirdParty::Fal.to_str(), "fal");
|
||||
assert_eq!(InferenceJobExternalThirdParty::Seedance2Pro.to_str(), "seedance2pro");
|
||||
assert_eq!(InferenceJobExternalThirdParty::Worldlabs.to_str(), "worldlabs");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceJobExternalThirdParty::from_str("fal").unwrap(), InferenceJobExternalThirdParty::Fal);
|
||||
assert_eq!(InferenceJobExternalThirdParty::from_str("seedance2pro").unwrap(), InferenceJobExternalThirdParty::Seedance2Pro);
|
||||
assert_eq!(InferenceJobExternalThirdParty::from_str("worldlabs").unwrap(), InferenceJobExternalThirdParty::Worldlabs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
const EXPECTED_COUNT : usize = 3;
|
||||
|
||||
assert_eq!(InferenceJobExternalThirdParty::all_variants().len(), EXPECTED_COUNT);
|
||||
assert_eq!(InferenceJobExternalThirdParty::iter().len(), EXPECTED_COUNT);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceJobExternalThirdParty::all_variants().len(), InferenceJobExternalThirdParty::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceJobExternalThirdParty::all_variants().len(), InferenceJobExternalThirdParty::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in InferenceJobExternalThirdParty::all_variants() {
|
||||
assert_eq!(variant, InferenceJobExternalThirdParty::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, InferenceJobExternalThirdParty::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, InferenceJobExternalThirdParty::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in InferenceJobExternalThirdParty::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-385
@@ -1,385 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `product_category`.
|
||||
///
|
||||
/// This is a user-facing and analytics-facing column that describes what product area the job
|
||||
/// is attributed to. For example, this will help us separate "video style transfer" from
|
||||
/// "storyteller studio" and also separate "live portrait" from "webcam live portrait".
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InferenceJobProductCategory {
|
||||
// =============== DOWNLOAD ===============
|
||||
|
||||
/// Download: GptSoVits
|
||||
#[default]
|
||||
DownloadGptSoVits,
|
||||
|
||||
// =============== FAL ===============
|
||||
|
||||
FalImage,
|
||||
FalVideo,
|
||||
/// Fal: 3D Object Generation
|
||||
FalObject,
|
||||
FalBgRemoval,
|
||||
|
||||
// =============== SEEDANCE 2 PRO ===============
|
||||
|
||||
#[serde(rename = "seedance2pro_video")]
|
||||
Seedance2ProVideo,
|
||||
|
||||
// =============== WORLD LABS ===============
|
||||
|
||||
/// World Labs: Gaussian Splat Generation
|
||||
#[serde(rename = "worldlabs_splat")]
|
||||
WorldlabsSplat,
|
||||
|
||||
// =============== TEXT TO SPEECH ===============
|
||||
|
||||
/// TTS: GptSoVits
|
||||
TtsGptSoVits,
|
||||
|
||||
/// TTS: F5Tts (Zero Shot)
|
||||
TtsF5,
|
||||
|
||||
/// TTS: StyleTts2 (Zero Shot)
|
||||
TtsStyleTts2,
|
||||
|
||||
/// TTS: Tacotron2
|
||||
TtsTacotron2,
|
||||
|
||||
// =============== VOICE CONVERSION ===============
|
||||
|
||||
/// Voice Conversion: RVC v2
|
||||
VcRvc2,
|
||||
|
||||
/// Voice Conversion: SoVitsSvc
|
||||
VcSvc,
|
||||
|
||||
VcSeedVc, // Ugh
|
||||
|
||||
// =============== VIDEO ===============
|
||||
|
||||
/// Video: Face Fusion (Lipsync)
|
||||
VidLipsyncFaceFusion,
|
||||
|
||||
/// Video: Sad Talker (Lipsync)
|
||||
VidLipsyncSadTalker,
|
||||
|
||||
/// Live Portrait (normal interface)
|
||||
VidLivePortrait,
|
||||
|
||||
/// Live Portrait (webcam interface)
|
||||
VidLivePortraitWebcam,
|
||||
|
||||
/// Video: Studio
|
||||
VidStudio,
|
||||
|
||||
/// Video: Studio Gen 2
|
||||
VidStudioGen2,
|
||||
|
||||
/// Video: Style Transfer
|
||||
VidStyleTransfer,
|
||||
|
||||
// =============== DEPRECATED ===============
|
||||
|
||||
/// Lipsync: Face Fusion
|
||||
#[deprecated(note = "Use `VidLipsyncFaceFusion` instead")]
|
||||
LipsyncFaceFusion,
|
||||
|
||||
/// Lipsync: SadTalker
|
||||
#[deprecated(note = "Use `VidLipsyncSadTalker` instead")]
|
||||
LipsyncSadTalker,
|
||||
|
||||
/// Live Portrait (normal interface)
|
||||
#[deprecated(note = "Use `VidLivePortrait` instead")]
|
||||
LivePortrait,
|
||||
|
||||
/// Live Portrait (webcam interface)
|
||||
#[deprecated(note = "Use `VidLivePortraitWebcam` instead")]
|
||||
LivePortraitWebcam,
|
||||
|
||||
/// Stable Diffusion (deprecated)
|
||||
#[deprecated(note = "unused")]
|
||||
StableDiffusion,
|
||||
|
||||
/// Storyteller Studio
|
||||
#[deprecated(note = "Use `VidStudio` instead")]
|
||||
Studio,
|
||||
|
||||
/// Lipsync: Face Fusion
|
||||
#[deprecated(note = "Use `VidLipsyncFaceFusion` instead")]
|
||||
VidFaceFusion,
|
||||
|
||||
/// Video Style Transfer
|
||||
#[deprecated(note = "Use `VidStyleTransfer` instead")]
|
||||
Vst,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceJobProductCategory);
|
||||
impl_mysql_enum_coders!(InferenceJobProductCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceJobProductCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::DownloadGptSoVits => "download_gpt_so_vits",
|
||||
Self::FalImage => "fal_image",
|
||||
Self::FalVideo => "fal_video",
|
||||
Self::FalObject => "fal_object",
|
||||
Self::FalBgRemoval => "fal_bg_removal",
|
||||
Self::Seedance2ProVideo => "seedance2pro_video",
|
||||
Self::WorldlabsSplat => "worldlabs_splat",
|
||||
Self::TtsGptSoVits => "tts_gpt_so_vits",
|
||||
Self::TtsStyleTts2 => "tts_style_tts2",
|
||||
Self::TtsTacotron2 => "tts_tacotron2",
|
||||
Self::TtsF5 => "tts_f5",
|
||||
Self::VcSvc => "vc_svc",
|
||||
Self::VcRvc2 => "vc_rvc2",
|
||||
Self::VcSeedVc => "vc_seed_vc",
|
||||
Self::VidLipsyncFaceFusion => "vid_lipsync_face_fusion",
|
||||
Self::VidLipsyncSadTalker => "vid_lipsync_sad_talker",
|
||||
Self::VidLivePortrait => "vid_live_portrait",
|
||||
Self::VidLivePortraitWebcam => "vid_live_portrait_webcam",
|
||||
Self::VidStudio => "vid_studio",
|
||||
Self::VidStudioGen2 => "vid_studio_gen2",
|
||||
Self::VidStyleTransfer => "vid_style_transfer",
|
||||
Self::LipsyncFaceFusion => "lipsync_face_fusion",
|
||||
Self::LipsyncSadTalker => "lipsync_sad_talker",
|
||||
Self::LivePortrait => "live_portrait",
|
||||
Self::LivePortraitWebcam => "live_portrait_webcam",
|
||||
Self::StableDiffusion => "stable_diffusion",
|
||||
Self::Studio => "studio",
|
||||
Self::VidFaceFusion => "vid_face_fusion",
|
||||
Self::Vst => "vst",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"download_gpt_so_vits" => Ok(Self::DownloadGptSoVits),
|
||||
"fal_image" => Ok(Self::FalImage),
|
||||
"fal_video" => Ok(Self::FalVideo),
|
||||
"fal_object" => Ok(Self::FalObject),
|
||||
"fal_bg_removal" => Ok(Self::FalBgRemoval),
|
||||
"seedance2pro_video" => Ok(Self::Seedance2ProVideo),
|
||||
"worldlabs_splat" => Ok(Self::WorldlabsSplat),
|
||||
"tts_gpt_so_vits" => Ok(Self::TtsGptSoVits),
|
||||
"tts_style_tts2" => Ok(Self::TtsStyleTts2),
|
||||
"tts_tacotron2" => Ok(Self::TtsTacotron2),
|
||||
"tts_f5" => Ok(Self::TtsF5),
|
||||
"vc_svc" => Ok(Self::VcSvc),
|
||||
"vc_rvc2" => Ok(Self::VcRvc2),
|
||||
"vc_seed_vc" => Ok(Self::VcSeedVc),
|
||||
"vid_lipsync_face_fusion" => Ok(Self::VidLipsyncFaceFusion),
|
||||
"vid_lipsync_sad_talker" => Ok(Self::VidLipsyncSadTalker),
|
||||
"vid_live_portrait" => Ok(Self::VidLivePortrait),
|
||||
"vid_live_portrait_webcam" => Ok(Self::VidLivePortraitWebcam),
|
||||
"vid_studio" => Ok(Self::VidStudio),
|
||||
"vid_studio_gen2" => Ok(Self::VidStudioGen2),
|
||||
"vid_style_transfer" => Ok(Self::VidStyleTransfer),
|
||||
"lipsync_face_fusion" => Ok(Self::LipsyncFaceFusion),
|
||||
"lipsync_sad_talker" => Ok(Self::LipsyncSadTalker),
|
||||
"live_portrait" => Ok(Self::LivePortrait),
|
||||
"live_portrait_webcam" => Ok(Self::LivePortraitWebcam),
|
||||
"stable_diffusion" => Ok(Self::StableDiffusion),
|
||||
"studio" => Ok(Self::Studio),
|
||||
"vid_face_fusion" => Ok(Self::VidFaceFusion),
|
||||
"vst" => Ok(Self::Vst),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::DownloadGptSoVits,
|
||||
Self::FalImage,
|
||||
Self::FalVideo,
|
||||
Self::FalObject,
|
||||
Self::FalBgRemoval,
|
||||
Self::Seedance2ProVideo,
|
||||
Self::WorldlabsSplat,
|
||||
Self::TtsGptSoVits,
|
||||
Self::TtsStyleTts2,
|
||||
Self::TtsTacotron2,
|
||||
Self::TtsF5,
|
||||
Self::VcSeedVc,
|
||||
Self::VcSvc,
|
||||
Self::VcRvc2,
|
||||
Self::VidLipsyncFaceFusion,
|
||||
Self::VidLipsyncSadTalker,
|
||||
Self::VidLivePortrait,
|
||||
Self::VidLivePortraitWebcam,
|
||||
Self::VidStudio,
|
||||
Self::VidStudioGen2,
|
||||
Self::VidStyleTransfer,
|
||||
Self::LipsyncFaceFusion,
|
||||
Self::LipsyncSadTalker,
|
||||
Self::LivePortrait,
|
||||
Self::LivePortraitWebcam,
|
||||
Self::StableDiffusion,
|
||||
Self::Studio,
|
||||
Self::VidFaceFusion,
|
||||
Self::Vst,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_job_product_category::InferenceJobProductCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceJobProductCategory::DownloadGptSoVits, "download_gpt_so_vits");
|
||||
assert_serialization(InferenceJobProductCategory::FalImage, "fal_image");
|
||||
assert_serialization(InferenceJobProductCategory::FalVideo, "fal_video");
|
||||
assert_serialization(InferenceJobProductCategory::FalObject, "fal_object");
|
||||
assert_serialization(InferenceJobProductCategory::FalBgRemoval, "fal_bg_removal");
|
||||
assert_serialization(InferenceJobProductCategory::Seedance2ProVideo, "seedance2pro_video");
|
||||
assert_serialization(InferenceJobProductCategory::WorldlabsSplat, "worldlabs_splat");
|
||||
assert_serialization(InferenceJobProductCategory::TtsGptSoVits, "tts_gpt_so_vits");
|
||||
assert_serialization(InferenceJobProductCategory::TtsStyleTts2, "tts_style_tts2");
|
||||
assert_serialization(InferenceJobProductCategory::TtsTacotron2, "tts_tacotron2");
|
||||
assert_serialization(InferenceJobProductCategory::TtsF5, "tts_f5");
|
||||
assert_serialization(InferenceJobProductCategory::VcRvc2, "vc_rvc2");
|
||||
assert_serialization(InferenceJobProductCategory::VcSvc, "vc_svc");
|
||||
assert_serialization(InferenceJobProductCategory::VcSvc, "vc_svc");
|
||||
assert_serialization(InferenceJobProductCategory::VidLipsyncFaceFusion, "vid_lipsync_face_fusion");
|
||||
assert_serialization(InferenceJobProductCategory::VidLipsyncSadTalker, "vid_lipsync_sad_talker");
|
||||
assert_serialization(InferenceJobProductCategory::VidLivePortrait, "vid_live_portrait");
|
||||
assert_serialization(InferenceJobProductCategory::VidLivePortraitWebcam, "vid_live_portrait_webcam");
|
||||
assert_serialization(InferenceJobProductCategory::VidStudio, "vid_studio");
|
||||
assert_serialization(InferenceJobProductCategory::VidStudioGen2, "vid_studio_gen2");
|
||||
assert_serialization(InferenceJobProductCategory::VidStyleTransfer, "vid_style_transfer");
|
||||
assert_serialization(InferenceJobProductCategory::LipsyncFaceFusion, "lipsync_face_fusion");
|
||||
assert_serialization(InferenceJobProductCategory::LipsyncSadTalker, "lipsync_sad_talker");
|
||||
assert_serialization(InferenceJobProductCategory::LivePortrait, "live_portrait");
|
||||
assert_serialization(InferenceJobProductCategory::LivePortraitWebcam, "live_portrait_webcam");
|
||||
assert_serialization(InferenceJobProductCategory::StableDiffusion, "stable_diffusion");
|
||||
assert_serialization(InferenceJobProductCategory::Studio, "studio");
|
||||
assert_serialization(InferenceJobProductCategory::VidFaceFusion, "vid_face_fusion");
|
||||
assert_serialization(InferenceJobProductCategory::Vst, "vst");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceJobProductCategory::DownloadGptSoVits.to_str(), "download_gpt_so_vits");
|
||||
assert_eq!(InferenceJobProductCategory::FalImage.to_str(), "fal_image");
|
||||
assert_eq!(InferenceJobProductCategory::FalVideo.to_str(), "fal_video");
|
||||
assert_eq!(InferenceJobProductCategory::FalObject.to_str(), "fal_object");
|
||||
assert_eq!(InferenceJobProductCategory::FalBgRemoval.to_str(), "fal_bg_removal");
|
||||
assert_eq!(InferenceJobProductCategory::Seedance2ProVideo.to_str(), "seedance2pro_video");
|
||||
assert_eq!(InferenceJobProductCategory::WorldlabsSplat.to_str(), "worldlabs_splat");
|
||||
assert_eq!(InferenceJobProductCategory::TtsGptSoVits.to_str(), "tts_gpt_so_vits");
|
||||
assert_eq!(InferenceJobProductCategory::TtsStyleTts2.to_str(), "tts_style_tts2");
|
||||
assert_eq!(InferenceJobProductCategory::TtsTacotron2.to_str(), "tts_tacotron2");
|
||||
assert_eq!(InferenceJobProductCategory::VcRvc2.to_str(), "vc_rvc2");
|
||||
assert_eq!(InferenceJobProductCategory::VcSvc.to_str(), "vc_svc");
|
||||
assert_eq!(InferenceJobProductCategory::VcSvc.to_str(), "vc_svc");
|
||||
assert_eq!(InferenceJobProductCategory::VidLipsyncFaceFusion.to_str(), "vid_lipsync_face_fusion");
|
||||
assert_eq!(InferenceJobProductCategory::VidLipsyncSadTalker.to_str(), "vid_lipsync_sad_talker");
|
||||
assert_eq!(InferenceJobProductCategory::VidLivePortrait.to_str(), "vid_live_portrait");
|
||||
assert_eq!(InferenceJobProductCategory::VidLivePortraitWebcam.to_str(), "vid_live_portrait_webcam");
|
||||
assert_eq!(InferenceJobProductCategory::VidStudio.to_str(), "vid_studio");
|
||||
assert_eq!(InferenceJobProductCategory::VidStudioGen2.to_str(), "vid_studio_gen2");
|
||||
assert_eq!(InferenceJobProductCategory::VidStyleTransfer.to_str(), "vid_style_transfer");
|
||||
assert_eq!(InferenceJobProductCategory::LipsyncFaceFusion.to_str(), "lipsync_face_fusion");
|
||||
assert_eq!(InferenceJobProductCategory::LipsyncSadTalker.to_str(), "lipsync_sad_talker");
|
||||
assert_eq!(InferenceJobProductCategory::LivePortrait.to_str(), "live_portrait");
|
||||
assert_eq!(InferenceJobProductCategory::LivePortraitWebcam.to_str(), "live_portrait_webcam");
|
||||
assert_eq!(InferenceJobProductCategory::StableDiffusion.to_str(), "stable_diffusion");
|
||||
assert_eq!(InferenceJobProductCategory::Studio.to_str(), "studio");
|
||||
assert_eq!(InferenceJobProductCategory::VidFaceFusion.to_str(), "vid_face_fusion");
|
||||
assert_eq!(InferenceJobProductCategory::Vst.to_str(), "vst");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceJobProductCategory::from_str("download_gpt_so_vits").unwrap(), InferenceJobProductCategory::DownloadGptSoVits);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("fal_image").unwrap(), InferenceJobProductCategory::FalImage);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("fal_video").unwrap(), InferenceJobProductCategory::FalVideo);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("fal_object").unwrap(), InferenceJobProductCategory::FalObject);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("fal_bg_removal").unwrap(), InferenceJobProductCategory::FalBgRemoval);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("seedance2pro_video").unwrap(), InferenceJobProductCategory::Seedance2ProVideo);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("worldlabs_splat").unwrap(), InferenceJobProductCategory::WorldlabsSplat);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("tts_gpt_so_vits").unwrap(), InferenceJobProductCategory::TtsGptSoVits);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("tts_style_tts2").unwrap(), InferenceJobProductCategory::TtsStyleTts2);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("tts_tacotron2").unwrap(), InferenceJobProductCategory::TtsTacotron2);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vc_rvc2").unwrap(), InferenceJobProductCategory::VcRvc2);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vc_svc").unwrap(), InferenceJobProductCategory::VcSvc);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vc_svc").unwrap(), InferenceJobProductCategory::VcSvc);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_lipsync_face_fusion").unwrap(), InferenceJobProductCategory::VidLipsyncFaceFusion);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_lipsync_sad_talker").unwrap(), InferenceJobProductCategory::VidLipsyncSadTalker);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_live_portrait").unwrap(), InferenceJobProductCategory::VidLivePortrait);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_live_portrait_webcam").unwrap(), InferenceJobProductCategory::VidLivePortraitWebcam);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_studio").unwrap(), InferenceJobProductCategory::VidStudio);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_studio_gen2").unwrap(), InferenceJobProductCategory::VidStudioGen2);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_style_transfer").unwrap(), InferenceJobProductCategory::VidStyleTransfer);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("lipsync_face_fusion").unwrap(), InferenceJobProductCategory::LipsyncFaceFusion);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("lipsync_sad_talker").unwrap(), InferenceJobProductCategory::LipsyncSadTalker);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("live_portrait").unwrap(), InferenceJobProductCategory::LivePortrait);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("live_portrait_webcam").unwrap(), InferenceJobProductCategory::LivePortraitWebcam);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("stable_diffusion").unwrap(), InferenceJobProductCategory::StableDiffusion);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("studio").unwrap(), InferenceJobProductCategory::Studio);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vid_face_fusion").unwrap(), InferenceJobProductCategory::VidFaceFusion);
|
||||
assert_eq!(InferenceJobProductCategory::from_str("vst").unwrap(), InferenceJobProductCategory::Vst);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
const EXPECTED_COUNT : usize = 29;
|
||||
|
||||
assert_eq!(InferenceJobProductCategory::all_variants().len(), EXPECTED_COUNT);
|
||||
assert_eq!(InferenceJobProductCategory::iter().len(), EXPECTED_COUNT);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceJobProductCategory::all_variants().len(), InferenceJobProductCategory::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceJobProductCategory::all_variants().len(), InferenceJobProductCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in InferenceJobProductCategory::all_variants() {
|
||||
assert_eq!(variant, InferenceJobProductCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, InferenceJobProductCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, InferenceJobProductCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in InferenceJobProductCategory::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-252
@@ -1,252 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `maybe_model_type`.
|
||||
///
|
||||
/// Our "generic inference" pipeline supports a wide variety of ML models and other media.
|
||||
/// Each inference "model type" identified by the following enum variants, though some pipelines
|
||||
/// may use multiple models or no model (and may report NULL).
|
||||
///
|
||||
/// These types are present in the HTTP API and database columns as serialized here.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum InferenceModelType {
|
||||
// TODO(bt,2024-07-15): This is too generic. We probably need "StorytellerStudio", "LivePortrait", etc.
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
// NB: sad_talker does use user-supplied models, so there is no "model token"
|
||||
#[serde(rename = "sad_talker")]
|
||||
SadTalker,
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
// TODO: Does this need to be "legacy_tacotron2" ?
|
||||
|
||||
#[serde(rename = "seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
/// NB: This is for Sora GPT 4o image gen
|
||||
#[serde(rename = "image_gen_api")]
|
||||
ImageGenApi,
|
||||
|
||||
#[serde(rename = "tacotron2")]
|
||||
Tacotron2,
|
||||
#[serde(rename = "vits")]
|
||||
Vits,
|
||||
#[serde(rename = "vall_e_x")]
|
||||
VallEX,
|
||||
#[serde(rename = "rerender_a_video")]
|
||||
RerenderAVideo,
|
||||
#[serde(rename = "stable_diffusion")]
|
||||
StableDiffusion,
|
||||
#[serde(rename = "mocap_net")]
|
||||
MocapNet,
|
||||
#[serde(rename = "styletts2")]
|
||||
StyleTTS2,
|
||||
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
|
||||
#[serde(rename = "convert_fbx_gltf")]
|
||||
ConvertFbxToGltf,
|
||||
#[serde(rename = "bvh_to_workflow")]
|
||||
BvhToWorkflow
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceModelType);
|
||||
impl_mysql_enum_coders!(InferenceModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::SadTalker => "sad_talker",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
Self::Tacotron2 => "tacotron2",
|
||||
Self::Vits => "vits",
|
||||
Self::VallEX => "vall_e_x",
|
||||
Self::RerenderAVideo => "rerender_a_video",
|
||||
Self::StableDiffusion => "stable_diffusion",
|
||||
Self::ImageGenApi => "image_gen_api",
|
||||
Self::SeedVc => "seed_vc",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
Self::ConvertFbxToGltf => "convert_fbx_gltf",
|
||||
Self::BvhToWorkflow => "bvh_to_workflow",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"sad_talker" => Ok(Self::SadTalker),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
"seed_vc" => Ok(Self::SeedVc),
|
||||
"tacotron2" => Ok(Self::Tacotron2),
|
||||
"vits" => Ok(Self::Vits),
|
||||
"vall_e_x" => Ok(Self::VallEX),
|
||||
"rerender_a_video" => Ok(Self::RerenderAVideo),
|
||||
"stable_diffusion" => Ok(Self::StableDiffusion),
|
||||
"image_gen_api" => Ok(Self::ImageGenApi),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
"convert_fbx_gltf" => Ok(Self::ConvertFbxToGltf),
|
||||
"bvh_to_workflow" => Ok(Self::BvhToWorkflow),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ComfyUi,
|
||||
Self::RvcV2,
|
||||
Self::SadTalker,
|
||||
Self::SoVitsSvc,
|
||||
Self::SeedVc,
|
||||
Self::Tacotron2,
|
||||
Self::Vits,
|
||||
Self::VallEX,
|
||||
Self::RerenderAVideo,
|
||||
Self::StableDiffusion,
|
||||
Self::ImageGenApi,
|
||||
Self::MocapNet,
|
||||
Self::StyleTTS2,
|
||||
Self::ConvertFbxToGltf,
|
||||
Self::BvhToWorkflow,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceModelType::RvcV2, "rvc_v2");
|
||||
assert_serialization(InferenceModelType::SadTalker, "sad_talker");
|
||||
assert_serialization(InferenceModelType::SeedVc, "seed_vc");
|
||||
assert_serialization(InferenceModelType::SoVitsSvc, "so_vits_svc");
|
||||
assert_serialization(InferenceModelType::Tacotron2, "tacotron2");
|
||||
assert_serialization(InferenceModelType::Vits, "vits");
|
||||
assert_serialization(InferenceModelType::VallEX, "vall_e_x");
|
||||
assert_serialization(InferenceModelType::RerenderAVideo, "rerender_a_video");
|
||||
assert_serialization(InferenceModelType::StableDiffusion, "stable_diffusion");
|
||||
assert_serialization(InferenceModelType::ImageGenApi, "image_gen_api");
|
||||
assert_serialization(InferenceModelType::MocapNet, "mocap_net");
|
||||
assert_serialization(InferenceModelType::ComfyUi, "comfy_ui");
|
||||
assert_serialization(InferenceModelType::StyleTTS2, "styletts2");
|
||||
assert_serialization(InferenceModelType::ConvertFbxToGltf, "convert_fbx_gltf");
|
||||
assert_serialization(InferenceModelType::BvhToWorkflow, "bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceModelType::ComfyUi.to_str(), "comfy_ui");
|
||||
assert_eq!(InferenceModelType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(InferenceModelType::SadTalker.to_str(), "sad_talker");
|
||||
assert_eq!(InferenceModelType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(InferenceModelType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(InferenceModelType::Tacotron2.to_str(), "tacotron2");
|
||||
assert_eq!(InferenceModelType::Vits.to_str(), "vits");
|
||||
assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x");
|
||||
assert_eq!(InferenceModelType::RerenderAVideo.to_str(), "rerender_a_video");
|
||||
assert_eq!(InferenceModelType::StableDiffusion.to_str(), "stable_diffusion");
|
||||
assert_eq!(InferenceModelType::ImageGenApi.to_str(), "image_gen_api");
|
||||
assert_eq!(InferenceModelType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(InferenceModelType::StyleTTS2.to_str(), "styletts2");
|
||||
assert_eq!(InferenceModelType::ConvertFbxToGltf.to_str(), "convert_fbx_gltf");
|
||||
assert_eq!(InferenceModelType::BvhToWorkflow.to_str(), "bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceModelType::from_str("rvc_v2").unwrap(), InferenceModelType::RvcV2);
|
||||
assert_eq!(InferenceModelType::from_str("sad_talker").unwrap(), InferenceModelType::SadTalker);
|
||||
assert_eq!(InferenceModelType::from_str("seed_vc").unwrap(), InferenceModelType::SeedVc);
|
||||
assert_eq!(InferenceModelType::from_str("so_vits_svc").unwrap(), InferenceModelType::SoVitsSvc);
|
||||
assert_eq!(InferenceModelType::from_str("tacotron2").unwrap(), InferenceModelType::Tacotron2);
|
||||
assert_eq!(InferenceModelType::from_str("vits").unwrap(), InferenceModelType::Vits);
|
||||
assert_eq!(InferenceModelType::from_str("vall_e_x").unwrap(), InferenceModelType::VallEX);
|
||||
assert_eq!(InferenceModelType::from_str("rerender_a_video").unwrap(), InferenceModelType::RerenderAVideo);
|
||||
assert_eq!(InferenceModelType::from_str("stable_diffusion").unwrap(), InferenceModelType::StableDiffusion);
|
||||
assert_eq!(InferenceModelType::from_str("image_gen_api").unwrap(), InferenceModelType::ImageGenApi);
|
||||
assert_eq!(InferenceModelType::from_str("mocap_net").unwrap(), InferenceModelType::MocapNet);
|
||||
assert_eq!(InferenceModelType::from_str("styletts2").unwrap(), InferenceModelType::StyleTTS2);
|
||||
assert_eq!(InferenceModelType::from_str("comfy_ui").unwrap(), InferenceModelType::ComfyUi);
|
||||
assert_eq!(InferenceModelType::from_str("convert_fbx_gltf").unwrap(), InferenceModelType::ConvertFbxToGltf);
|
||||
assert_eq!(InferenceModelType::from_str("bvh_to_workflow").unwrap(), InferenceModelType::BvhToWorkflow);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceModelType::all_variants();
|
||||
assert_eq!(variants.len(), 15);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SeedVc));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::Tacotron2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::Vits));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::VallEX));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RerenderAVideo));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StableDiffusion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ImageGenApi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ConvertFbxToGltf));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::BvhToWorkflow));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceModelType::all_variants().len(), InferenceModelType::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceModelType::all_variants().len(), InferenceModelType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in InferenceModelType::all_variants() {
|
||||
assert_eq!(variant, InferenceModelType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, InferenceModelType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, InferenceModelType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in InferenceModelType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_inference_jobs` table in `VARCHAR(32)` field `on_success_result_entity_type`.
|
||||
///
|
||||
/// Our "generic inference" pipeline supports a wide variety of output types.
|
||||
/// Each "result type" is identified by the following enum variants.
|
||||
///
|
||||
/// These types are present in the HTTP API and database columns as serialized here.
|
||||
///
|
||||
/// YOU CAN ADD NEW VALUES, BUT DO NOT CHANGE EXISTING VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum InferenceResultType {
|
||||
/// Result is stored in the "media_files" table.
|
||||
/// (The upstream model could have produced any type of media - image, video, audio. That is irrelevant.)
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
#[serde(rename = "text_to_speech")]
|
||||
TextToSpeech,
|
||||
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversion,
|
||||
|
||||
#[serde(rename = "zs_voice_embedding")]
|
||||
ZeroShotVoiceEmbedding,
|
||||
|
||||
#[serde(rename = "upload_model")]
|
||||
UploadModel
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(InferenceResultType);
|
||||
impl_mysql_enum_coders!(InferenceResultType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl InferenceResultType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::ZeroShotVoiceEmbedding => "zs_voice_embedding",
|
||||
Self::UploadModel => "upload_model",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"zs_voice_embedding" => Ok(Self::ZeroShotVoiceEmbedding),
|
||||
"upload_model" => Ok(Self::UploadModel),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<InferenceResultType> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
InferenceResultType::MediaFile,
|
||||
InferenceResultType::TextToSpeech,
|
||||
InferenceResultType::VoiceConversion,
|
||||
InferenceResultType::ZeroShotVoiceEmbedding,
|
||||
InferenceResultType::UploadModel,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceResultType::MediaFile, "media_file");
|
||||
assert_serialization(InferenceResultType::TextToSpeech, "text_to_speech");
|
||||
assert_serialization(InferenceResultType::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(InferenceResultType::ZeroShotVoiceEmbedding, "zs_voice_embedding");
|
||||
assert_serialization(InferenceResultType::UploadModel, "upload_model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceResultType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(InferenceResultType::TextToSpeech.to_str(), "text_to_speech");
|
||||
assert_eq!(InferenceResultType::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(InferenceResultType::ZeroShotVoiceEmbedding.to_str(), "zs_voice_embedding");
|
||||
assert_eq!(InferenceResultType::UploadModel.to_str(), "upload_model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceResultType::from_str("media_file").unwrap(), InferenceResultType::MediaFile);
|
||||
assert_eq!(InferenceResultType::from_str("text_to_speech").unwrap(), InferenceResultType::TextToSpeech);
|
||||
assert_eq!(InferenceResultType::from_str("voice_conversion").unwrap(), InferenceResultType::VoiceConversion);
|
||||
assert_eq!(InferenceResultType::from_str("zs_voice_embedding").unwrap(), InferenceResultType::ZeroShotVoiceEmbedding);
|
||||
assert_eq!(InferenceResultType::from_str("upload_model").unwrap(), InferenceResultType::UploadModel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceResultType::all_variants();
|
||||
assert_eq!(variants.len(), 5);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::TextToSpeech));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::VoiceConversion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::ZeroShotVoiceEmbedding));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::UploadModel));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(InferenceResultType::all_variants().len(), InferenceResultType::iter().len());
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
pub mod frontend_failure_category;
|
||||
pub mod inference_category;
|
||||
pub mod inference_input_source_token_type;
|
||||
pub mod inference_job_external_third_party;
|
||||
pub mod inference_job_product_category;
|
||||
// Moved to enums_db crate:
|
||||
// pub mod inference_job_type;
|
||||
pub mod inference_model_type;
|
||||
pub mod inference_result_type;
|
||||
@@ -1,259 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `generic_synthetic_ids` table in `VARCHAR(32)` field `id_category`.
|
||||
///
|
||||
/// This lets us create synthetic increment IDs on a per-user, per-category basis.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum IdCategory {
|
||||
/// media_files table
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// Results from lipsync animations (which may live in the media_files table)
|
||||
#[serde(rename = "lipsync_animation")]
|
||||
LipsyncAnimationResult,
|
||||
|
||||
/// Results from face fusion
|
||||
#[serde(rename = "face_fusion")]
|
||||
FaceFusionResult,
|
||||
|
||||
/// Results from video filters
|
||||
#[serde(rename = "video_filter")]
|
||||
VideoFilterResult,
|
||||
|
||||
/// Results from Live Portrait
|
||||
#[serde(rename = "live_portrait")]
|
||||
LivePortraitResult,
|
||||
|
||||
/// Studio Renders
|
||||
#[serde(rename = "studio_render")]
|
||||
StudioRender,
|
||||
|
||||
/// Results from mocap
|
||||
#[serde(rename = "mocap")]
|
||||
MocapResult,
|
||||
|
||||
/// Results from workflows
|
||||
#[serde(rename = "workflow")]
|
||||
WorkflowResult,
|
||||
|
||||
/// Results from tacotron2
|
||||
/// Applies for RVC and SVC
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// Results from voice conversion (which may live in the media_files table)
|
||||
/// Applies for RVC and SVC
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversionResult,
|
||||
|
||||
/// Results from the zero shot tts (which may live in the media_files table)
|
||||
#[serde(rename = "zs_tts_result")]
|
||||
ZeroShotTtsResult,
|
||||
|
||||
/// Zs dataset which lives in the zs_voice_datasets table
|
||||
#[serde(rename = "zs_dataset")]
|
||||
ZeroShotVoiceDataset,
|
||||
|
||||
/// Zs voice which lives in the zs_voices table
|
||||
#[serde(rename = "zs_voice")]
|
||||
ZeroShotVoiceEmbedding,
|
||||
|
||||
#[serde(rename = "model_weights")]
|
||||
ModelWeights,
|
||||
|
||||
/// Files that are uploaded with no general product area they belong to. (Eg. local dev testing)
|
||||
#[serde(rename = "file_upload")]
|
||||
FileUpload,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(IdCategory);
|
||||
impl_mysql_enum_coders!(IdCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl IdCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::LipsyncAnimationResult => "lipsync_animation",
|
||||
Self::FaceFusionResult => "face_fusion",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::VoiceConversionResult => "voice_conversion",
|
||||
Self::ZeroShotVoiceDataset => "zs_dataset",
|
||||
Self::ZeroShotVoiceEmbedding => "zs_voice",
|
||||
Self::ZeroShotTtsResult => "zs_tts_result",
|
||||
Self::VideoFilterResult => "video_filter",
|
||||
Self::LivePortraitResult => "live_portrait",
|
||||
Self::StudioRender => "studio_render",
|
||||
Self::ModelWeights => "model_weights",
|
||||
Self::FileUpload => "file_upload",
|
||||
Self::MocapResult => "mocap",
|
||||
Self::WorkflowResult => "workflow",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"lipsync_animation" => Ok(Self::LipsyncAnimationResult),
|
||||
"face_fusion" => Ok(Self::FaceFusionResult),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"voice_conversion" => Ok(Self::VoiceConversionResult),
|
||||
"zs_dataset" => Ok(Self::ZeroShotVoiceDataset),
|
||||
"zs_voice" => Ok(Self::ZeroShotVoiceEmbedding),
|
||||
"zs_tts_result" => Ok(Self::ZeroShotTtsResult),
|
||||
"video_filter" => Ok(Self::VideoFilterResult),
|
||||
"live_portrait" => Ok(Self::LivePortraitResult),
|
||||
"studio_render" => Ok(Self::StudioRender),
|
||||
"model_weights" => Ok(Self::ModelWeights),
|
||||
"file_upload" => Ok(Self::FileUpload),
|
||||
"mocap" => Ok(Self::MocapResult),
|
||||
"workflow" => Ok(Self::WorkflowResult),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::MediaFile,
|
||||
Self::LipsyncAnimationResult,
|
||||
Self::FaceFusionResult,
|
||||
Self::VideoFilterResult,
|
||||
Self::LivePortraitResult,
|
||||
Self::StudioRender,
|
||||
Self::TtsResult,
|
||||
Self::VoiceConversionResult,
|
||||
Self::ZeroShotTtsResult,
|
||||
Self::ZeroShotVoiceDataset,
|
||||
Self::ZeroShotVoiceEmbedding,
|
||||
Self::ModelWeights,
|
||||
Self::FileUpload,
|
||||
Self::MocapResult,
|
||||
Self::WorkflowResult,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::generic_synthetic_ids::id_category::IdCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(IdCategory::MediaFile, "media_file");
|
||||
assert_serialization(IdCategory::LipsyncAnimationResult, "lipsync_animation");
|
||||
assert_serialization(IdCategory::FaceFusionResult, "face_fusion");
|
||||
assert_serialization(IdCategory::VideoFilterResult, "video_filter");
|
||||
assert_serialization(IdCategory::LivePortraitResult, "live_portrait");
|
||||
assert_serialization(IdCategory::StudioRender, "studio_render");
|
||||
assert_serialization(IdCategory::TtsResult, "tts_result");
|
||||
assert_serialization(IdCategory::VoiceConversionResult, "voice_conversion");
|
||||
assert_serialization(IdCategory::ZeroShotVoiceDataset, "zs_dataset");
|
||||
assert_serialization(IdCategory::ZeroShotVoiceEmbedding, "zs_voice");
|
||||
assert_serialization(IdCategory::ZeroShotTtsResult, "zs_tts_result");
|
||||
assert_serialization(IdCategory::ModelWeights, "model_weights");
|
||||
assert_serialization(IdCategory::FileUpload, "file_upload");
|
||||
assert_serialization(IdCategory::MocapResult, "mocap");
|
||||
assert_serialization(IdCategory::WorkflowResult, "workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(IdCategory::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(IdCategory::LipsyncAnimationResult.to_str(), "lipsync_animation");
|
||||
assert_eq!(IdCategory::FaceFusionResult.to_str(), "face_fusion");
|
||||
assert_eq!(IdCategory::VideoFilterResult.to_str(), "video_filter");
|
||||
assert_eq!(IdCategory::LivePortraitResult.to_str(), "live_portrait");
|
||||
assert_eq!(IdCategory::StudioRender.to_str(), "studio_render");
|
||||
assert_eq!(IdCategory::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(IdCategory::VoiceConversionResult.to_str(), "voice_conversion");
|
||||
assert_eq!(IdCategory::ZeroShotVoiceDataset.to_str(), "zs_dataset");
|
||||
assert_eq!(IdCategory::ZeroShotVoiceEmbedding.to_str(), "zs_voice");
|
||||
assert_eq!(IdCategory::ZeroShotTtsResult.to_str(), "zs_tts_result");
|
||||
assert_eq!(IdCategory::ModelWeights.to_str(), "model_weights");
|
||||
assert_eq!(IdCategory::FileUpload.to_str(), "file_upload");
|
||||
assert_eq!(IdCategory::MocapResult.to_str(), "mocap");
|
||||
assert_eq!(IdCategory::WorkflowResult.to_str(), "workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile);
|
||||
assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimationResult);
|
||||
assert_eq!(IdCategory::from_str("face_fusion").unwrap(), IdCategory::FaceFusionResult);
|
||||
assert_eq!(IdCategory::from_str("video_filter").unwrap(), IdCategory::VideoFilterResult);
|
||||
assert_eq!(IdCategory::from_str("live_portrait").unwrap(), IdCategory::LivePortraitResult);
|
||||
assert_eq!(IdCategory::from_str("studio_render").unwrap(), IdCategory::StudioRender);
|
||||
assert_eq!(IdCategory::from_str("tts_result").unwrap(), IdCategory::TtsResult);
|
||||
assert_eq!(IdCategory::from_str("voice_conversion").unwrap(), IdCategory::VoiceConversionResult);
|
||||
assert_eq!(IdCategory::from_str("zs_dataset").unwrap(), IdCategory::ZeroShotVoiceDataset);
|
||||
assert_eq!(IdCategory::from_str("zs_voice").unwrap(), IdCategory::ZeroShotVoiceEmbedding);
|
||||
assert_eq!(IdCategory::from_str("zs_tts_result").unwrap(), IdCategory::ZeroShotTtsResult);
|
||||
assert_eq!(IdCategory::from_str("model_weights").unwrap(), IdCategory::ModelWeights);
|
||||
assert_eq!(IdCategory::from_str("file_upload").unwrap(), IdCategory::FileUpload);
|
||||
assert_eq!(IdCategory::from_str("mocap").unwrap(), IdCategory::MocapResult);
|
||||
assert_eq!(IdCategory::from_str("workflow").unwrap(), IdCategory::WorkflowResult);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = IdCategory::all_variants();
|
||||
assert_eq!(variants.len(), 15);
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::FaceFusionResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::VideoFilterResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::LivePortraitResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::StudioRender));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::MocapResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::WorkflowResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::TtsResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversionResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotTtsResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotVoiceDataset));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotVoiceEmbedding));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ModelWeights));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::FileUpload));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(IdCategory::all_variants().len(), IdCategory::iter().len());
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(IdCategory::all_variants().len(), IdCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in IdCategory::all_variants() {
|
||||
assert_eq!(variant, IdCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, IdCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, IdCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod id_category;
|
||||
@@ -1,245 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MediaFileAnimationType {
|
||||
/// Body: No body animation or rig.
|
||||
/// Face: Rig supporting ARKit face blendshapes, or ARKit data
|
||||
ArKit,
|
||||
|
||||
/// Body: Animation or rig for MikuMikuDance (MMD).
|
||||
/// Face: No face animation.
|
||||
MikuMikuDance,
|
||||
|
||||
/// Body: Animation or rig for MikuMikuDance (MMD).
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
MikuMikuDanceArKit,
|
||||
|
||||
/// Body: Animation or rig for Mixamo
|
||||
/// Face: No face animation.
|
||||
Mixamo,
|
||||
|
||||
/// Body: Animation or rig for Mixamo
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
MixamoArKit,
|
||||
|
||||
/// Body: Animation or rig by MocapNet
|
||||
/// Face: No face animation.
|
||||
MocapNet,
|
||||
|
||||
/// Body: Animation or rig for MocapNet
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
MocapNetArKit,
|
||||
|
||||
/// Body: Animation or rig by Move.ai
|
||||
/// Face: No face animation.
|
||||
MoveAi,
|
||||
|
||||
/// Body: Animation or rig for Move.ai
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
MoveAiArKit,
|
||||
|
||||
/// Body: Animation or rig for Rigify.
|
||||
/// Face: No face animation.
|
||||
Rigify,
|
||||
|
||||
/// Body: Animation or rig for Rigify.
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
RigifyArKit,
|
||||
|
||||
/// Body: Animation or rig for Rokoko.
|
||||
/// Face: No face animation.
|
||||
Rokoko,
|
||||
|
||||
/// Body: Animation or rig for Rokoko.
|
||||
/// Face: Animation blendshapes for ARKit.
|
||||
RokokoArKit,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileAnimationType);
|
||||
impl_mysql_enum_coders!(MediaFileAnimationType);
|
||||
impl_mysql_from_row!(MediaFileAnimationType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileAnimationType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ArKit => "ar_kit",
|
||||
Self::MikuMikuDance => "miku_miku_dance",
|
||||
Self::MikuMikuDanceArKit => "miku_miku_dance_ar_kit",
|
||||
Self::Mixamo => "mixamo",
|
||||
Self::MixamoArKit => "mixamo_ar_kit",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::MocapNetArKit => "mocap_net_ar_kit",
|
||||
Self::MoveAi => "move_ai",
|
||||
Self::MoveAiArKit => "move_ai_ar_kit",
|
||||
Self::Rigify => "rigify",
|
||||
Self::RigifyArKit => "rigify_ar_kit",
|
||||
Self::Rokoko => "rokoko",
|
||||
Self::RokokoArKit => "rokoko_ar_kit",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"ar_kit" => Ok(Self::ArKit),
|
||||
"miku_miku_dance" => Ok(Self::MikuMikuDance),
|
||||
"miku_miku_dance_ar_kit" => Ok(Self::MikuMikuDanceArKit),
|
||||
"mixamo" => Ok(Self::Mixamo),
|
||||
"mixamo_ar_kit" => Ok(Self::MixamoArKit),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"mocap_net_ar_kit" => Ok(Self::MocapNetArKit),
|
||||
"move_ai" => Ok(Self::MoveAi),
|
||||
"move_ai_ar_kit" => Ok(Self::MoveAiArKit),
|
||||
"rigify" => Ok(Self::Rigify),
|
||||
"rigify_ar_kit" => Ok(Self::RigifyArKit),
|
||||
"rokoko" => Ok(Self::Rokoko),
|
||||
"rokoko_ar_kit" => Ok(Self::RokokoArKit),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ArKit,
|
||||
Self::MikuMikuDance,
|
||||
Self::MikuMikuDanceArKit,
|
||||
Self::Mixamo,
|
||||
Self::MixamoArKit,
|
||||
Self::MocapNet,
|
||||
Self::MocapNetArKit,
|
||||
Self::MoveAi,
|
||||
Self::MoveAiArKit,
|
||||
Self::Rigify,
|
||||
Self::RigifyArKit,
|
||||
Self::Rokoko,
|
||||
Self::RokokoArKit,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_animation_type::MediaFileAnimationType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileAnimationType::ArKit, "ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::MikuMikuDance, "miku_miku_dance");
|
||||
assert_serialization(MediaFileAnimationType::MikuMikuDanceArKit, "miku_miku_dance_ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::Mixamo, "mixamo");
|
||||
assert_serialization(MediaFileAnimationType::MixamoArKit, "mixamo_ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::MocapNet, "mocap_net");
|
||||
assert_serialization(MediaFileAnimationType::MocapNetArKit, "mocap_net_ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::MoveAi, "move_ai");
|
||||
assert_serialization(MediaFileAnimationType::MoveAiArKit, "move_ai_ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::Rigify, "rigify");
|
||||
assert_serialization(MediaFileAnimationType::RigifyArKit, "rigify_ar_kit");
|
||||
assert_serialization(MediaFileAnimationType::Rokoko, "rokoko");
|
||||
assert_serialization(MediaFileAnimationType::RokokoArKit, "rokoko_ar_kit");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileAnimationType::ArKit.to_str(), "ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::MikuMikuDance.to_str(), "miku_miku_dance");
|
||||
assert_eq!(MediaFileAnimationType::MikuMikuDanceArKit.to_str(), "miku_miku_dance_ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::Mixamo.to_str(), "mixamo");
|
||||
assert_eq!(MediaFileAnimationType::MixamoArKit.to_str(), "mixamo_ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(MediaFileAnimationType::MocapNetArKit.to_str(), "mocap_net_ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::MoveAi.to_str(), "move_ai");
|
||||
assert_eq!(MediaFileAnimationType::MoveAiArKit.to_str(), "move_ai_ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::Rigify.to_str(), "rigify");
|
||||
assert_eq!(MediaFileAnimationType::RigifyArKit.to_str(), "rigify_ar_kit");
|
||||
assert_eq!(MediaFileAnimationType::Rokoko.to_str(), "rokoko");
|
||||
assert_eq!(MediaFileAnimationType::RokokoArKit.to_str(), "rokoko_ar_kit");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileAnimationType::from_str("ar_kit").unwrap(), MediaFileAnimationType::ArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("miku_miku_dance").unwrap(), MediaFileAnimationType::MikuMikuDance);
|
||||
assert_eq!(MediaFileAnimationType::from_str("miku_miku_dance_ar_kit").unwrap(), MediaFileAnimationType::MikuMikuDanceArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("mixamo").unwrap(), MediaFileAnimationType::Mixamo);
|
||||
assert_eq!(MediaFileAnimationType::from_str("mixamo_ar_kit").unwrap(), MediaFileAnimationType::MixamoArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("mocap_net").unwrap(), MediaFileAnimationType::MocapNet);
|
||||
assert_eq!(MediaFileAnimationType::from_str("mocap_net_ar_kit").unwrap(), MediaFileAnimationType::MocapNetArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("move_ai").unwrap(), MediaFileAnimationType::MoveAi);
|
||||
assert_eq!(MediaFileAnimationType::from_str("move_ai_ar_kit").unwrap(), MediaFileAnimationType::MoveAiArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("rigify").unwrap(), MediaFileAnimationType::Rigify);
|
||||
assert_eq!(MediaFileAnimationType::from_str("rigify_ar_kit").unwrap(), MediaFileAnimationType::RigifyArKit);
|
||||
assert_eq!(MediaFileAnimationType::from_str("rokoko").unwrap(), MediaFileAnimationType::Rokoko);
|
||||
assert_eq!(MediaFileAnimationType::from_str("rokoko_ar_kit").unwrap(), MediaFileAnimationType::RokokoArKit);
|
||||
assert!(MediaFileAnimationType::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileAnimationType::all_variants();
|
||||
assert_eq!(variants.len(), 13);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::ArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MikuMikuDance));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MikuMikuDanceArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::Mixamo));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MixamoArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MocapNetArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MoveAi));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::MoveAiArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::Rigify));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::RigifyArKit));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::Rokoko));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileAnimationType::RokokoArKit));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileAnimationType::all_variants().len(), MediaFileAnimationType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileAnimationType::all_variants() {
|
||||
assert_eq!(variant, MediaFileAnimationType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileAnimationType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileAnimationType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in MediaFileAnimationType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MediaFileClass {
|
||||
/// Unknown (default value)
|
||||
/// This will be present until we migrate all old files.
|
||||
Unknown,
|
||||
|
||||
/// Audio files: wav, mp3, etc.
|
||||
Audio,
|
||||
|
||||
/// Image files: png, jpeg, etc.
|
||||
Image,
|
||||
|
||||
/// Video files: mp4, etc.
|
||||
Video,
|
||||
|
||||
/// 3D engine data: glb, gltf, etc.
|
||||
Dimensional,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileClass);
|
||||
impl_mysql_enum_coders!(MediaFileClass);
|
||||
impl_mysql_from_row!(MediaFileClass);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileClass {
|
||||
pub const fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Unknown => "unknown",
|
||||
Self::Audio => "audio",
|
||||
Self::Image => "image",
|
||||
Self::Video => "video",
|
||||
Self::Dimensional => "dimensional",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"unknown" => Ok(Self::Unknown),
|
||||
"audio" => Ok(Self::Audio),
|
||||
"image" => Ok(Self::Image),
|
||||
"video" => Ok(Self::Video),
|
||||
"dimensional" => Ok(Self::Dimensional),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Unknown,
|
||||
Self::Audio,
|
||||
Self::Image,
|
||||
Self::Video,
|
||||
Self::Dimensional,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileClass::Unknown, "unknown");
|
||||
assert_serialization(MediaFileClass::Audio, "audio");
|
||||
assert_serialization(MediaFileClass::Image, "image");
|
||||
assert_serialization(MediaFileClass::Video, "video");
|
||||
assert_serialization(MediaFileClass::Dimensional, "dimensional");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(MediaFileClass::Unknown.to_str(), "unknown");
|
||||
assert_eq!(MediaFileClass::Audio.to_str(), "audio");
|
||||
assert_eq!(MediaFileClass::Image.to_str(), "image");
|
||||
assert_eq!(MediaFileClass::Video.to_str(), "video");
|
||||
assert_eq!(MediaFileClass::Dimensional.to_str(), "dimensional");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(MediaFileClass::from_str("unknown").unwrap(), MediaFileClass::Unknown);
|
||||
assert_eq!(MediaFileClass::from_str("audio").unwrap(), MediaFileClass::Audio);
|
||||
assert_eq!(MediaFileClass::from_str("image").unwrap(), MediaFileClass::Image);
|
||||
assert_eq!(MediaFileClass::from_str("video").unwrap(), MediaFileClass::Video);
|
||||
assert_eq!(MediaFileClass::from_str("dimensional").unwrap(), MediaFileClass::Dimensional);
|
||||
assert!(MediaFileClass::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileClass::all_variants();
|
||||
assert_eq!(variants.len(), 5);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileClass::Unknown));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileClass::Audio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileClass::Image));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileClass::Video));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileClass::Dimensional));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileClass::all_variants().len(), MediaFileClass::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileClass::all_variants() {
|
||||
assert_eq!(variant, MediaFileClass::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileClass::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileClass::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in MediaFileClass::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MediaFileEngineCategory {
|
||||
/// A 3D scene full of objects, characters, animations, etc.
|
||||
Scene,
|
||||
|
||||
/// A 3D character model.
|
||||
Character,
|
||||
|
||||
/// A 3D non-humanoid model, e.g. dragon, wolf, slime creature, etc.
|
||||
/// These may or may not have a skeleton that can be animated with IK/FK.
|
||||
Creature,
|
||||
|
||||
/// A 3D skeletal animation sequence that can be applied to a character,
|
||||
/// creature, etc. Typically, these use Mixamo or Move.ai.
|
||||
Animation,
|
||||
|
||||
/// A facial blend shape / shape key animation. Currently, these
|
||||
/// are 100% ARKit.
|
||||
Expression,
|
||||
|
||||
/// A large 3D object that can be used as a backdrop for a scene,
|
||||
/// a.k.a. "set", "stage", etc. These are typically self-contained
|
||||
/// locations, buildings, or environments.
|
||||
Location,
|
||||
|
||||
/// All items used to add atmosphere to a scene, e.g. furniture, plants,
|
||||
/// vehicles, radios, and certain props. (We'll reserve the word props for
|
||||
/// "hand props" later.)
|
||||
SetDressing,
|
||||
|
||||
/// A 3D object that doesn't fit with the other types.
|
||||
Object,
|
||||
|
||||
/// A 3D skybox.
|
||||
Skybox,
|
||||
|
||||
/// An Image Plane (texture that spawns as an object)
|
||||
ImagePlane,
|
||||
|
||||
/// A Video Plane (texture that spawns as an object)
|
||||
VideoPlane,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileEngineCategory);
|
||||
impl_mysql_enum_coders!(MediaFileEngineCategory);
|
||||
impl_mysql_from_row!(MediaFileEngineCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileEngineCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Scene => "scene",
|
||||
Self::Character => "character",
|
||||
Self::Creature => "creature",
|
||||
Self::Animation => "animation",
|
||||
Self::Expression => "expression",
|
||||
Self::Location => "location",
|
||||
Self::SetDressing => "set_dressing",
|
||||
Self::Object => "object",
|
||||
Self::Skybox => "skybox",
|
||||
Self::ImagePlane => "image_plane",
|
||||
Self::VideoPlane => "video_plane",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"scene" => Ok(Self::Scene),
|
||||
"character" => Ok(Self::Character),
|
||||
"creature" => Ok(Self::Creature),
|
||||
"animation" => Ok(Self::Animation),
|
||||
"expression" => Ok(Self::Expression),
|
||||
"location" => Ok(Self::Location),
|
||||
"set_dressing" => Ok(Self::SetDressing),
|
||||
"object" => Ok(Self::Object),
|
||||
"skybox" => Ok(Self::Skybox),
|
||||
"image_plane" => Ok(Self::ImagePlane),
|
||||
"video_plane" => Ok(Self::VideoPlane),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Scene,
|
||||
Self::Character,
|
||||
Self::Creature,
|
||||
Self::Animation,
|
||||
Self::Expression,
|
||||
Self::Location,
|
||||
Self::SetDressing,
|
||||
Self::Object,
|
||||
Self::Skybox,
|
||||
Self::ImagePlane,
|
||||
Self::VideoPlane,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileEngineCategory::Scene, "scene");
|
||||
assert_serialization(MediaFileEngineCategory::Character, "character");
|
||||
assert_serialization(MediaFileEngineCategory::Creature, "creature");
|
||||
assert_serialization(MediaFileEngineCategory::Animation, "animation");
|
||||
assert_serialization(MediaFileEngineCategory::Expression, "expression");
|
||||
assert_serialization(MediaFileEngineCategory::Location, "location");
|
||||
assert_serialization(MediaFileEngineCategory::SetDressing, "set_dressing");
|
||||
assert_serialization(MediaFileEngineCategory::Object, "object");
|
||||
assert_serialization(MediaFileEngineCategory::Skybox, "skybox");
|
||||
assert_serialization(MediaFileEngineCategory::ImagePlane, "image_plane");
|
||||
assert_serialization(MediaFileEngineCategory::VideoPlane, "video_plane");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileEngineCategory::Scene.to_str(), "scene");
|
||||
assert_eq!(MediaFileEngineCategory::Character.to_str(), "character");
|
||||
assert_eq!(MediaFileEngineCategory::Creature.to_str(), "creature");
|
||||
assert_eq!(MediaFileEngineCategory::Animation.to_str(), "animation");
|
||||
assert_eq!(MediaFileEngineCategory::Expression.to_str(), "expression");
|
||||
assert_eq!(MediaFileEngineCategory::Location.to_str(), "location");
|
||||
assert_eq!(MediaFileEngineCategory::SetDressing.to_str(), "set_dressing");
|
||||
assert_eq!(MediaFileEngineCategory::Object.to_str(), "object");
|
||||
assert_eq!(MediaFileEngineCategory::Skybox.to_str(), "skybox");
|
||||
assert_eq!(MediaFileEngineCategory::ImagePlane.to_str(), "image_plane");
|
||||
assert_eq!(MediaFileEngineCategory::VideoPlane.to_str(), "video_plane");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileEngineCategory::from_str("scene").unwrap(), MediaFileEngineCategory::Scene);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("character").unwrap(), MediaFileEngineCategory::Character);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("creature").unwrap(), MediaFileEngineCategory::Creature);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("animation").unwrap(), MediaFileEngineCategory::Animation);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("expression").unwrap(), MediaFileEngineCategory::Expression);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("location").unwrap(), MediaFileEngineCategory::Location);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("set_dressing").unwrap(), MediaFileEngineCategory::SetDressing);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("object").unwrap(), MediaFileEngineCategory::Object);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("skybox").unwrap(), MediaFileEngineCategory::Skybox);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("image_plane").unwrap(), MediaFileEngineCategory::ImagePlane);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("video_plane").unwrap(), MediaFileEngineCategory::VideoPlane);
|
||||
assert!(MediaFileEngineCategory::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileEngineCategory::all_variants();
|
||||
assert_eq!(variants.len(), 11);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Scene));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Character));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Creature));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Animation));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Expression));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Location));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::SetDressing));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Object));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Skybox));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::ImagePlane));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::VideoPlane));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileEngineCategory::all_variants().len(), MediaFileEngineCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileEngineCategory::all_variants() {
|
||||
assert_eq!(variant, MediaFileEngineCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileEngineCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileEngineCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in MediaFileEngineCategory::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MediaFileOriginCategory {
|
||||
/// ML model inference output - uploaded models or zero shot.
|
||||
Inference,
|
||||
|
||||
/// Processed results - (we don't have these systems yet, but eg. trim, transcode, etc).
|
||||
Processed,
|
||||
|
||||
/// User uploaded files (from their filesystem)
|
||||
Upload,
|
||||
|
||||
/// User uploaded files recorded directly from their device (browser, mobile), typically using device APIs.
|
||||
DeviceApi,
|
||||
|
||||
/// From Storyteller Studio Engine
|
||||
#[deprecated(note="This db field should only denote file provenance, not the product.")]
|
||||
#[serde(rename = "studio")]
|
||||
StorytellerStudio,
|
||||
|
||||
/// From Storyteller Studio Engine
|
||||
#[deprecated(note = "DO NOT USE. Originally deprecated in favor of `StorytellerStudio`.")]
|
||||
StoryEngine,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileOriginCategory);
|
||||
impl_mysql_enum_coders!(MediaFileOriginCategory);
|
||||
impl_mysql_from_row!(MediaFileOriginCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileOriginCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Inference => "inference",
|
||||
Self::Processed => "processed",
|
||||
Self::Upload => "upload",
|
||||
Self::DeviceApi => "device_api",
|
||||
Self::StorytellerStudio => "studio",
|
||||
Self::StoryEngine => "story_engine",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"inference" => Ok(Self::Inference),
|
||||
"processed" => Ok(Self::Processed),
|
||||
"upload" => Ok(Self::Upload),
|
||||
"device_api" => Ok(Self::DeviceApi),
|
||||
"studio" => Ok(Self::StorytellerStudio),
|
||||
"story_engine" => Ok(Self::StoryEngine),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Inference,
|
||||
Self::Processed,
|
||||
Self::Upload,
|
||||
Self::DeviceApi,
|
||||
Self::StorytellerStudio,
|
||||
Self::StoryEngine,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileOriginCategory::Inference, "inference");
|
||||
assert_serialization(MediaFileOriginCategory::Processed, "processed");
|
||||
assert_serialization(MediaFileOriginCategory::Upload, "upload");
|
||||
assert_serialization(MediaFileOriginCategory::DeviceApi, "device_api");
|
||||
assert_serialization(MediaFileOriginCategory::StorytellerStudio, "studio");
|
||||
assert_serialization(MediaFileOriginCategory::StoryEngine, "story_engine");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileOriginCategory::Inference.to_str(), "inference");
|
||||
assert_eq!(MediaFileOriginCategory::Processed.to_str(), "processed");
|
||||
assert_eq!(MediaFileOriginCategory::Upload.to_str(), "upload");
|
||||
assert_eq!(MediaFileOriginCategory::DeviceApi.to_str(), "device_api");
|
||||
assert_eq!(MediaFileOriginCategory::StorytellerStudio.to_str(), "studio");
|
||||
assert_eq!(MediaFileOriginCategory::StoryEngine.to_str(), "story_engine");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileOriginCategory::from_str("inference").unwrap(), MediaFileOriginCategory::Inference);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("processed").unwrap(), MediaFileOriginCategory::Processed);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("upload").unwrap(), MediaFileOriginCategory::Upload);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("device_api").unwrap(), MediaFileOriginCategory::DeviceApi);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("studio").unwrap(), MediaFileOriginCategory::StorytellerStudio);
|
||||
assert_eq!(MediaFileOriginCategory::from_str("story_engine").unwrap(), MediaFileOriginCategory::StoryEngine);
|
||||
assert!(MediaFileOriginCategory::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginCategory::all_variants();
|
||||
assert_eq!(variants.len(), 6);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Inference));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Processed));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::Upload));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::DeviceApi));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::StorytellerStudio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginCategory::StoryEngine));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileOriginCategory::all_variants().len(), MediaFileOriginCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileOriginCategory::all_variants() {
|
||||
assert_eq!(variant, MediaFileOriginCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileOriginCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileOriginCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in MediaFileOriginCategory::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-280
@@ -1,280 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in `VARCHAR(16)` field `origin_product_category`.
|
||||
///
|
||||
/// This value indicates what product originally created the media file. (Not the ML model or
|
||||
/// user upload process.) This will let us scope media files to the product that generated them
|
||||
/// and filter them out of unrelated products if necessary (eg. a user probably doesn't want
|
||||
/// "Voice Designer" dataset samples in a video generation flow.)
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum MediaFileOriginProductCategory {
|
||||
/// Unknown which product is attached to the file (generated the file, the file was
|
||||
/// uploaded on behalf of, etc.)
|
||||
#[serde(rename = "unknown")]
|
||||
Unknown,
|
||||
|
||||
/// Media files created by (or uploaded for) the Face Animator product.
|
||||
/// The underlying model could be SadTalker, Wav2Lip, or some future model
|
||||
#[serde(rename = "face_animator")]
|
||||
FaceAnimator,
|
||||
|
||||
/// Media files created by Face Fusion (lipsync)
|
||||
#[serde(rename = "face_fusion")]
|
||||
FaceFusion,
|
||||
|
||||
/// Media files created by Face Mirror (currently powered by Live Portrait)
|
||||
#[serde(rename = "face_mirror")]
|
||||
FaceMirror,
|
||||
|
||||
/// Video style transfer
|
||||
#[serde(rename = "vst")]
|
||||
VideoStyleTransfer,
|
||||
|
||||
/// Image Studio
|
||||
#[serde(rename = "image_studio")]
|
||||
ImageStudio,
|
||||
|
||||
/// Storyteller Studio
|
||||
#[serde(rename = "studio")]
|
||||
StorytellerStudio,
|
||||
|
||||
/// Text to speech (Tacotron2, not voice designer / VallE-X)
|
||||
#[serde(rename = "tts")]
|
||||
TextToSpeech,
|
||||
|
||||
/// Voice conversion (either RVC or SVC)
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversion,
|
||||
|
||||
/// Media files created by (or uploaded for) the Zero Shot voice product.
|
||||
#[serde(rename = "zs_voice")]
|
||||
ZeroShotVoice,
|
||||
|
||||
// Mocap
|
||||
#[serde(rename = "mocap")]
|
||||
Mocap,
|
||||
|
||||
#[serde(rename = "image_gen")]
|
||||
ImageGeneration,
|
||||
|
||||
#[serde(rename = "video_gen")]
|
||||
VideoGeneration,
|
||||
|
||||
#[serde(rename = "world_gen")]
|
||||
WorldGeneration,
|
||||
|
||||
// Media files for video filters
|
||||
#[deprecated(note = "This isn't relevant product surface area anymore")]
|
||||
#[serde(rename = "video_filter")]
|
||||
VideoFilter,
|
||||
|
||||
// Workflow
|
||||
#[deprecated(note = "Use studio and VST instead.")]
|
||||
#[serde(rename = "workflow")]
|
||||
Workflow,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileOriginProductCategory);
|
||||
impl_mysql_enum_coders!(MediaFileOriginProductCategory);
|
||||
impl_mysql_from_row!(MediaFileOriginProductCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileOriginProductCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Unknown => "unknown",
|
||||
Self::FaceAnimator => "face_animator",
|
||||
Self::FaceFusion => "face_fusion",
|
||||
Self::FaceMirror => "face_mirror",
|
||||
Self::VideoStyleTransfer => "vst",
|
||||
Self::ImageStudio => "image_studio",
|
||||
Self::StorytellerStudio => "studio",
|
||||
Self::TextToSpeech => "tts",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::ZeroShotVoice => "zs_voice",
|
||||
Self::Mocap => "mocap",
|
||||
Self::ImageGeneration => "image_gen",
|
||||
Self::VideoGeneration => "video_gen",
|
||||
Self::WorldGeneration => "world_gen",
|
||||
Self::VideoFilter => "video_filter",
|
||||
Self::Workflow => "workflow",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"unknown" => Ok(Self::Unknown),
|
||||
"face_animator" => Ok(Self::FaceAnimator),
|
||||
"face_fusion" => Ok(Self::FaceFusion),
|
||||
"face_mirror" => Ok(Self::FaceMirror),
|
||||
"vst" => Ok(Self::VideoStyleTransfer),
|
||||
"image_studio" => Ok(Self::ImageStudio),
|
||||
"studio" => Ok(Self::StorytellerStudio),
|
||||
"tts" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"zs_voice" => Ok(Self::ZeroShotVoice),
|
||||
"mocap" => Ok(Self::Mocap),
|
||||
"image_gen" => Ok(Self::ImageGeneration),
|
||||
"video_gen" => Ok(Self::VideoGeneration),
|
||||
"world_gen" => Ok(Self::WorldGeneration),
|
||||
"video_filter" => Ok(Self::VideoFilter),
|
||||
"workflow" => Ok(Self::Workflow),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Unknown,
|
||||
Self::FaceAnimator,
|
||||
Self::FaceFusion,
|
||||
Self::FaceMirror,
|
||||
Self::VideoStyleTransfer,
|
||||
Self::ImageStudio,
|
||||
Self::StorytellerStudio,
|
||||
Self::TextToSpeech,
|
||||
Self::VoiceConversion,
|
||||
Self::ZeroShotVoice,
|
||||
Self::Mocap,
|
||||
Self::ImageGeneration,
|
||||
Self::VideoGeneration,
|
||||
Self::WorldGeneration,
|
||||
Self::VideoFilter,
|
||||
Self::Workflow,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileOriginProductCategory::Unknown, "unknown");
|
||||
assert_serialization(MediaFileOriginProductCategory::FaceAnimator, "face_animator");
|
||||
assert_serialization(MediaFileOriginProductCategory::FaceFusion, "face_fusion");
|
||||
assert_serialization(MediaFileOriginProductCategory::FaceMirror, "face_mirror");
|
||||
assert_serialization(MediaFileOriginProductCategory::VideoStyleTransfer, "vst");
|
||||
assert_serialization(MediaFileOriginProductCategory::ImageStudio, "image_studio");
|
||||
assert_serialization(MediaFileOriginProductCategory::StorytellerStudio, "studio");
|
||||
assert_serialization(MediaFileOriginProductCategory::TextToSpeech, "tts");
|
||||
assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(MediaFileOriginProductCategory::ZeroShotVoice, "zs_voice");
|
||||
assert_serialization(MediaFileOriginProductCategory::Mocap, "mocap");
|
||||
assert_serialization(MediaFileOriginProductCategory::ImageGeneration, "image_gen");
|
||||
assert_serialization(MediaFileOriginProductCategory::VideoGeneration, "video_gen");
|
||||
assert_serialization(MediaFileOriginProductCategory::WorldGeneration, "world_gen");
|
||||
assert_serialization(MediaFileOriginProductCategory::VideoFilter, "video_filter");
|
||||
assert_serialization(MediaFileOriginProductCategory::Workflow, "workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(MediaFileOriginProductCategory::Unknown.to_str(), "unknown");
|
||||
assert_eq!(MediaFileOriginProductCategory::FaceAnimator.to_str(), "face_animator");
|
||||
assert_eq!(MediaFileOriginProductCategory::FaceFusion.to_str(), "face_fusion");
|
||||
assert_eq!(MediaFileOriginProductCategory::FaceMirror.to_str(), "face_mirror");
|
||||
assert_eq!(MediaFileOriginProductCategory::VideoStyleTransfer.to_str(), "vst");
|
||||
assert_eq!(MediaFileOriginProductCategory::ImageStudio.to_str(), "image_studio");
|
||||
assert_eq!(MediaFileOriginProductCategory::StorytellerStudio.to_str(), "studio");
|
||||
assert_eq!(MediaFileOriginProductCategory::TextToSpeech.to_str(), "tts");
|
||||
assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(MediaFileOriginProductCategory::ZeroShotVoice.to_str(), "zs_voice");
|
||||
assert_eq!(MediaFileOriginProductCategory::Mocap.to_str(), "mocap");
|
||||
assert_eq!(MediaFileOriginProductCategory::ImageGeneration.to_str(), "image_gen");
|
||||
assert_eq!(MediaFileOriginProductCategory::VideoGeneration.to_str(), "video_gen");
|
||||
assert_eq!(MediaFileOriginProductCategory::WorldGeneration.to_str(), "world_gen");
|
||||
assert_eq!(MediaFileOriginProductCategory::VideoFilter.to_str(), "video_filter");
|
||||
assert_eq!(MediaFileOriginProductCategory::Workflow.to_str(), "workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("unknown").unwrap(), MediaFileOriginProductCategory::Unknown);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("face_animator").unwrap(), MediaFileOriginProductCategory::FaceAnimator);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("face_fusion").unwrap(), MediaFileOriginProductCategory::FaceFusion);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("face_mirror").unwrap(), MediaFileOriginProductCategory::FaceMirror);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("vst").unwrap(), MediaFileOriginProductCategory::VideoStyleTransfer);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("image_studio").unwrap(), MediaFileOriginProductCategory::ImageStudio);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("studio").unwrap(), MediaFileOriginProductCategory::StorytellerStudio);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("tts").unwrap(), MediaFileOriginProductCategory::TextToSpeech);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("zs_voice").unwrap(), MediaFileOriginProductCategory::ZeroShotVoice);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("mocap").unwrap(), MediaFileOriginProductCategory::Mocap);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("image_gen").unwrap(),MediaFileOriginProductCategory::ImageGeneration);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("video_gen").unwrap(), MediaFileOriginProductCategory::VideoGeneration);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("world_gen").unwrap(), MediaFileOriginProductCategory::WorldGeneration);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("video_filter").unwrap(), MediaFileOriginProductCategory::VideoFilter);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("workflow").unwrap(), MediaFileOriginProductCategory::Workflow);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginProductCategory::all_variants();
|
||||
assert_eq!(variants.len(), 16);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceAnimator));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceFusion));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceMirror));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VideoStyleTransfer));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ImageStudio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::StorytellerStudio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::TextToSpeech));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ZeroShotVoice));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Mocap));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ImageGeneration));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VideoGeneration));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::WorldGeneration));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VideoFilter));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Workflow));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileOriginProductCategory::all_variants().len(), MediaFileOriginProductCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileOriginProductCategory::all_variants() {
|
||||
assert_eq!(variant, MediaFileOriginProductCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileOriginProductCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileOriginProductCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in MediaFileOriginProductCategory::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[deprecated(note = "This was primarily for Bevy")]
|
||||
pub enum MediaFileSubtype {
|
||||
/// NB: MediaFileSubtype is deprecated.
|
||||
/// This should signal that the field / enum is fully deprecated.
|
||||
Deprecated,
|
||||
|
||||
// TODO(bt,2024-04-22): Deprecated (migrate)
|
||||
/// Animation file from Mixamo
|
||||
/// Primarily used for FBX and GLB.
|
||||
Mixamo,
|
||||
|
||||
// TODO(bt,2024-04-22): Deprecated (migrate)
|
||||
/// Animation file from MocapNet
|
||||
/// Primarily used for BVH.
|
||||
MocapNet,
|
||||
|
||||
// TODO(bt,2024-04-22): Deprecated
|
||||
/// Generic animation case
|
||||
/// Used for BVH files, but can also pertain to animation-only files of other types.
|
||||
AnimationOnly,
|
||||
|
||||
// TODO(bt,2024-04-22): Deprecated
|
||||
/// Generic 3D scene file.
|
||||
/// Can pertain to glTF, glB, FBX, etc.
|
||||
SceneImport,
|
||||
|
||||
// TODO(bt,2024-04-22): Deprecated
|
||||
/// Native Storyteller scene format.
|
||||
/// Typically stored in a `.scn.ron` file.
|
||||
StorytellerScene,
|
||||
|
||||
/// A 3D scene full of objects, characters, animations, etc.
|
||||
Scene,
|
||||
|
||||
/// A 3D character model.
|
||||
Character,
|
||||
|
||||
/// A 3D animation.
|
||||
Animation,
|
||||
|
||||
/// A 3D object that doesn't fit with the other types.
|
||||
Object,
|
||||
|
||||
/// A 3D skybox.
|
||||
Skybox,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileSubtype);
|
||||
impl_mysql_enum_coders!(MediaFileSubtype);
|
||||
impl_mysql_from_row!(MediaFileSubtype);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileSubtype {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Deprecated => "deprecated",
|
||||
Self::Mixamo => "mixamo",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::AnimationOnly => "animation_only",
|
||||
Self::SceneImport => "scene_import",
|
||||
Self::StorytellerScene => "storyteller_scene",
|
||||
Self::Scene => "scene",
|
||||
Self::Character => "character",
|
||||
Self::Animation => "animation",
|
||||
Self::Object => "object",
|
||||
Self::Skybox => "skybox",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"deprecated" => Ok(Self::Deprecated),
|
||||
"mixamo" => Ok(Self::Mixamo),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"animation_only" => Ok(Self::AnimationOnly),
|
||||
"scene_import" => Ok(Self::SceneImport),
|
||||
"storyteller_scene" => Ok(Self::StorytellerScene),
|
||||
"scene" => Ok(Self::Scene),
|
||||
"character" => Ok(Self::Character),
|
||||
"animation" => Ok(Self::Animation),
|
||||
"object" => Ok(Self::Object),
|
||||
"skybox" => Ok(Self::Skybox),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Deprecated,
|
||||
Self::Mixamo,
|
||||
Self::MocapNet,
|
||||
Self::AnimationOnly,
|
||||
Self::SceneImport,
|
||||
Self::StorytellerScene,
|
||||
Self::Scene,
|
||||
Self::Character,
|
||||
Self::Animation,
|
||||
Self::Object,
|
||||
Self::Skybox,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_subtype::MediaFileSubtype;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileSubtype::Deprecated, "deprecated");
|
||||
assert_serialization(MediaFileSubtype::Mixamo, "mixamo");
|
||||
assert_serialization(MediaFileSubtype::MocapNet, "mocap_net");
|
||||
assert_serialization(MediaFileSubtype::AnimationOnly, "animation_only");
|
||||
assert_serialization(MediaFileSubtype::SceneImport, "scene_import");
|
||||
assert_serialization(MediaFileSubtype::StorytellerScene, "storyteller_scene");
|
||||
assert_serialization(MediaFileSubtype::Scene, "scene");
|
||||
assert_serialization(MediaFileSubtype::Character, "character");
|
||||
assert_serialization(MediaFileSubtype::Animation, "animation");
|
||||
assert_serialization(MediaFileSubtype::Object, "object");
|
||||
assert_serialization(MediaFileSubtype::Skybox, "skybox");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileSubtype::Deprecated.to_str(), "deprecated");
|
||||
assert_eq!(MediaFileSubtype::Mixamo.to_str(), "mixamo");
|
||||
assert_eq!(MediaFileSubtype::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(MediaFileSubtype::AnimationOnly.to_str(), "animation_only");
|
||||
assert_eq!(MediaFileSubtype::SceneImport.to_str(), "scene_import");
|
||||
assert_eq!(MediaFileSubtype::StorytellerScene.to_str(), "storyteller_scene");
|
||||
assert_eq!(MediaFileSubtype::Scene.to_str(), "scene");
|
||||
assert_eq!(MediaFileSubtype::Character.to_str(), "character");
|
||||
assert_eq!(MediaFileSubtype::Animation.to_str(), "animation");
|
||||
assert_eq!(MediaFileSubtype::Object.to_str(), "object");
|
||||
assert_eq!(MediaFileSubtype::Skybox.to_str(), "skybox");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileSubtype::from_str("deprecated").unwrap(), MediaFileSubtype::Deprecated);
|
||||
assert_eq!(MediaFileSubtype::from_str("mixamo").unwrap(), MediaFileSubtype::Mixamo);
|
||||
assert_eq!(MediaFileSubtype::from_str("mocap_net").unwrap(), MediaFileSubtype::MocapNet);
|
||||
assert_eq!(MediaFileSubtype::from_str("animation_only").unwrap(), MediaFileSubtype::AnimationOnly);
|
||||
assert_eq!(MediaFileSubtype::from_str("scene_import").unwrap(), MediaFileSubtype::SceneImport);
|
||||
assert_eq!(MediaFileSubtype::from_str("storyteller_scene").unwrap(), MediaFileSubtype::StorytellerScene);
|
||||
assert_eq!(MediaFileSubtype::from_str("scene").unwrap(), MediaFileSubtype::Scene);
|
||||
assert_eq!(MediaFileSubtype::from_str("character").unwrap(), MediaFileSubtype::Character);
|
||||
assert_eq!(MediaFileSubtype::from_str("animation").unwrap(), MediaFileSubtype::Animation);
|
||||
assert_eq!(MediaFileSubtype::from_str("object").unwrap(), MediaFileSubtype::Object);
|
||||
assert_eq!(MediaFileSubtype::from_str("skybox").unwrap(), MediaFileSubtype::Skybox);
|
||||
assert!(MediaFileSubtype::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileSubtype::all_variants();
|
||||
assert_eq!(variants.len(), 11);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Deprecated));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Mixamo));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::AnimationOnly));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::SceneImport));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::StorytellerScene));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Scene));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Character));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Animation));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Object));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileSubtype::Skybox));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileSubtype::all_variants().len(), MediaFileSubtype::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileSubtype::all_variants() {
|
||||
assert_eq!(variant, MediaFileSubtype::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileSubtype::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileSubtype::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in MediaFileSubtype::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `media_files` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MediaFileType {
|
||||
// TODO(bt): Deprecate and split into audio mime types; use media_class to represent broadly
|
||||
/// Audio files: wav, mp3, etc.
|
||||
#[deprecated]
|
||||
Audio,
|
||||
|
||||
// TODO(bt): Deprecate and split into image mime types; use media_class to represent broadly
|
||||
/// Image files: png, jpeg, etc.
|
||||
#[deprecated]
|
||||
Image,
|
||||
|
||||
// TODO(bt): Deprecate and split into video mime types; use media_class to represent broadly
|
||||
/// Video files: mp4, etc.
|
||||
#[deprecated]
|
||||
Video,
|
||||
|
||||
/// BVH files (for Bevy)
|
||||
/// NB: This is the new type to migrate to.
|
||||
Bvh,
|
||||
|
||||
/// FBX files (for Bevy)
|
||||
Fbx,
|
||||
|
||||
/// glTF binary files (for Bevy)
|
||||
Glb,
|
||||
|
||||
/// glTF files (for Bevy)
|
||||
Gltf,
|
||||
|
||||
/// Spz Gaussian splats
|
||||
/// This is a standard file format for Gaussian Splats, used by World Labs.
|
||||
/// The mime type is application/gzip.
|
||||
Spz,
|
||||
|
||||
/// Bevy's scene files (in RON; Rusty Object Notation)
|
||||
/// This will be replaced with another format in future versions of Bevy
|
||||
SceneRon,
|
||||
|
||||
/// Alternate scene files.
|
||||
SceneJson,
|
||||
|
||||
/// "Polygon Model Data", character data for MikuMikuDance
|
||||
/// See: https://mikumikudance.fandom.com/wiki/MMD:Polygon_Model_Data
|
||||
Pmd,
|
||||
|
||||
/// "Vocaloid Motion Data", animation data for MikuMikuDance
|
||||
/// See: https://mikumikudance.fandom.com/wiki/VMD_file_format
|
||||
Vmd,
|
||||
|
||||
/// "Polygon Model eXtend", character data from MikuMikuDance
|
||||
/// NB: this is often associated with external files for textures, which
|
||||
/// we'll store in the same bucket path.
|
||||
/// See: https://mikumikudance.fandom.com/wiki/MMD:Polygon_Model_eXtend
|
||||
Pmx,
|
||||
|
||||
/// CSV format. (We use these for ArKit)
|
||||
Csv,
|
||||
|
||||
/// Jpeg images
|
||||
Jpg,
|
||||
|
||||
/// Png images
|
||||
Png,
|
||||
|
||||
/// Gif images
|
||||
Gif,
|
||||
|
||||
/// Mp4 videos
|
||||
Mp4,
|
||||
|
||||
/// Wav audio
|
||||
Wav,
|
||||
|
||||
/// Mp3 audio
|
||||
Mp3,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaFileType);
|
||||
impl_mysql_enum_coders!(MediaFileType);
|
||||
impl_mysql_from_row!(MediaFileType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaFileType {
|
||||
|
||||
/// Jpeg and Png are the most widely supported static image formats for AI inference.
|
||||
/// Webp, Webm, and Gif aren't as widely supported, so we don't include them here.
|
||||
pub fn is_jpg_or_png(&self) -> bool {
|
||||
matches!(self, Self::Jpg | Self::Png)
|
||||
}
|
||||
|
||||
/// A little bit less strict than `is_jpg_or_png`, this includes the legacy `Image` type.
|
||||
pub fn is_jpg_or_png_or_legacy_image(&self) -> bool {
|
||||
matches!(self, Self::Jpg | Self::Png | Self::Image)
|
||||
}
|
||||
|
||||
/// Returns the `MediaFileType` if the mime type matches one of the known types.
|
||||
/// This is not exhaustive.
|
||||
/// (NB: In general we shouldn't keep much application logic in the `enums` crate,
|
||||
/// but this is a good case for it.)
|
||||
pub fn try_from_mime_type(mime_type: &str) -> Option<Self> {
|
||||
match mime_type {
|
||||
"image/jpeg" => Some(Self::Jpg),
|
||||
"image/png" => Some(Self::Png),
|
||||
"video/mp4" => Some(Self::Mp4),
|
||||
"model/gltf-binary" => Some(Self::Glb),
|
||||
//"audio/wav" => Some(Self::Wav), // NB: Not sure if this is correct
|
||||
//"audio/mpeg" => Some(Self::Mp3), // NB: Not sure if this is correct
|
||||
//"image/gif" => Some(Self::Gif), // NB: Not sure if this is correct
|
||||
//"model/gltf+json" => Some(Self::Gltf), // NB: Not sure if this is correct
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Audio => "audio",
|
||||
Self::Image => "image",
|
||||
Self::Video => "video",
|
||||
Self::Bvh => "bvh",
|
||||
Self::Fbx => "fbx",
|
||||
Self::Glb => "glb",
|
||||
Self::Gltf => "gltf",
|
||||
Self::Spz => "spz",
|
||||
Self::SceneRon => "scene_ron",
|
||||
Self::SceneJson => "scene_json",
|
||||
Self::Pmd => "pmd",
|
||||
Self::Vmd => "vmd",
|
||||
Self::Pmx => "pmx",
|
||||
Self::Csv => "csv",
|
||||
Self::Jpg => "jpg",
|
||||
Self::Png => "png",
|
||||
Self::Gif => "gif",
|
||||
Self::Mp4 => "mp4",
|
||||
Self::Wav => "wav",
|
||||
Self::Mp3 => "mp3",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"audio" => Ok(Self::Audio),
|
||||
"image" => Ok(Self::Image),
|
||||
"video" => Ok(Self::Video),
|
||||
"bvh" => Ok(Self::Bvh),
|
||||
"fbx" => Ok(Self::Fbx),
|
||||
"glb" => Ok(Self::Glb),
|
||||
"gltf" => Ok(Self::Gltf),
|
||||
"spz" => Ok(Self::Spz),
|
||||
"scene_ron" => Ok(Self::SceneRon),
|
||||
"scene_json" => Ok(Self::SceneJson),
|
||||
"pmd" => Ok(Self::Pmd),
|
||||
"vmd" => Ok(Self::Vmd),
|
||||
"pmx" => Ok(Self::Pmx),
|
||||
"csv" => Ok(Self::Csv),
|
||||
"jpg" => Ok(Self::Jpg),
|
||||
"png" => Ok(Self::Png),
|
||||
"gif" => Ok(Self::Gif),
|
||||
"mp4" => Ok(Self::Mp4),
|
||||
"wav" => Ok(Self::Wav),
|
||||
"mp3" => Ok(Self::Mp3),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Audio,
|
||||
Self::Image,
|
||||
Self::Video,
|
||||
Self::Bvh,
|
||||
Self::Fbx,
|
||||
Self::Glb,
|
||||
Self::Gltf,
|
||||
Self::Spz,
|
||||
Self::SceneRon,
|
||||
Self::SceneJson,
|
||||
Self::Pmd,
|
||||
Self::Vmd,
|
||||
Self::Pmx,
|
||||
Self::Csv,
|
||||
Self::Jpg,
|
||||
Self::Png,
|
||||
Self::Gif,
|
||||
Self::Mp4,
|
||||
Self::Wav,
|
||||
Self::Mp3,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_files::media_file_type::MediaFileType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod utility {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_jpg_or_png() {
|
||||
// True
|
||||
assert!(MediaFileType::Jpg.is_jpg_or_png());
|
||||
assert!(MediaFileType::Png.is_jpg_or_png());
|
||||
|
||||
// Assert these image types are false
|
||||
assert!(!MediaFileType::Gif.is_jpg_or_png());
|
||||
assert!(!MediaFileType::Image.is_jpg_or_png());
|
||||
|
||||
// Everything else is false
|
||||
for variant in MediaFileType::all_variants() {
|
||||
if matches!(variant, MediaFileType::Jpg | MediaFileType::Png) {
|
||||
continue;
|
||||
}
|
||||
assert!(!variant.is_jpg_or_png(), "Expected {:?} to not be jpg or png", variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileType::Audio, "audio");
|
||||
assert_serialization(MediaFileType::Image, "image");
|
||||
assert_serialization(MediaFileType::Video, "video");
|
||||
assert_serialization(MediaFileType::Bvh, "bvh");
|
||||
assert_serialization(MediaFileType::Fbx, "fbx");
|
||||
assert_serialization(MediaFileType::Glb, "glb");
|
||||
assert_serialization(MediaFileType::Gltf, "gltf");
|
||||
assert_serialization(MediaFileType::Spz, "spz");
|
||||
assert_serialization(MediaFileType::SceneRon, "scene_ron");
|
||||
assert_serialization(MediaFileType::SceneJson, "scene_json");
|
||||
assert_serialization(MediaFileType::Pmd, "pmd");
|
||||
assert_serialization(MediaFileType::Vmd, "vmd");
|
||||
assert_serialization(MediaFileType::Pmx, "pmx");
|
||||
assert_serialization(MediaFileType::Csv, "csv");
|
||||
assert_serialization(MediaFileType::Jpg, "jpg");
|
||||
assert_serialization(MediaFileType::Png, "png");
|
||||
assert_serialization(MediaFileType::Gif, "gif");
|
||||
assert_serialization(MediaFileType::Mp4, "mp4");
|
||||
assert_serialization(MediaFileType::Wav, "wav");
|
||||
assert_serialization(MediaFileType::Mp3, "mp3");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(MediaFileType::Audio.to_str(), "audio");
|
||||
assert_eq!(MediaFileType::Image.to_str(), "image");
|
||||
assert_eq!(MediaFileType::Video.to_str(), "video");
|
||||
assert_eq!(MediaFileType::Bvh.to_str(), "bvh");
|
||||
assert_eq!(MediaFileType::Fbx.to_str(), "fbx");
|
||||
assert_eq!(MediaFileType::Glb.to_str(), "glb");
|
||||
assert_eq!(MediaFileType::Gltf.to_str(), "gltf");
|
||||
assert_eq!(MediaFileType::Spz.to_str(), "spz");
|
||||
assert_eq!(MediaFileType::SceneRon.to_str(), "scene_ron");
|
||||
assert_eq!(MediaFileType::SceneJson.to_str(), "scene_json");
|
||||
assert_eq!(MediaFileType::Pmd.to_str(), "pmd");
|
||||
assert_eq!(MediaFileType::Vmd.to_str(), "vmd");
|
||||
assert_eq!(MediaFileType::Pmx.to_str(), "pmx");
|
||||
assert_eq!(MediaFileType::Csv.to_str(), "csv");
|
||||
assert_eq!(MediaFileType::Jpg.to_str(), "jpg");
|
||||
assert_eq!(MediaFileType::Png.to_str(), "png");
|
||||
assert_eq!(MediaFileType::Gif.to_str(), "gif");
|
||||
assert_eq!(MediaFileType::Mp4.to_str(), "mp4");
|
||||
assert_eq!(MediaFileType::Wav.to_str(), "wav");
|
||||
assert_eq!(MediaFileType::Mp3.to_str(), "mp3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(MediaFileType::from_str("audio").unwrap(), MediaFileType::Audio);
|
||||
assert_eq!(MediaFileType::from_str("image").unwrap(), MediaFileType::Image);
|
||||
assert_eq!(MediaFileType::from_str("video").unwrap(), MediaFileType::Video);
|
||||
assert_eq!(MediaFileType::from_str("bvh").unwrap(), MediaFileType::Bvh);
|
||||
assert_eq!(MediaFileType::from_str("fbx").unwrap(), MediaFileType::Fbx);
|
||||
assert_eq!(MediaFileType::from_str("glb").unwrap(), MediaFileType::Glb);
|
||||
assert_eq!(MediaFileType::from_str("gltf").unwrap(), MediaFileType::Gltf);
|
||||
assert_eq!(MediaFileType::from_str("spz").unwrap(), MediaFileType::Spz);
|
||||
assert_eq!(MediaFileType::from_str("scene_ron").unwrap(), MediaFileType::SceneRon);
|
||||
assert_eq!(MediaFileType::from_str("scene_json").unwrap(), MediaFileType::SceneJson);
|
||||
assert_eq!(MediaFileType::from_str("pmd").unwrap(), MediaFileType::Pmd);
|
||||
assert_eq!(MediaFileType::from_str("vmd").unwrap(), MediaFileType::Vmd);
|
||||
assert_eq!(MediaFileType::from_str("pmx").unwrap(), MediaFileType::Pmx);
|
||||
assert_eq!(MediaFileType::from_str("csv").unwrap(), MediaFileType::Csv);
|
||||
assert_eq!(MediaFileType::from_str("jpg").unwrap(), MediaFileType::Jpg);
|
||||
assert_eq!(MediaFileType::from_str("png").unwrap(), MediaFileType::Png);
|
||||
assert_eq!(MediaFileType::from_str("gif").unwrap(), MediaFileType::Gif);
|
||||
assert_eq!(MediaFileType::from_str("mp4").unwrap(), MediaFileType::Mp4);
|
||||
assert_eq!(MediaFileType::from_str("wav").unwrap(), MediaFileType::Wav);
|
||||
assert_eq!(MediaFileType::from_str("mp3").unwrap(), MediaFileType::Mp3);
|
||||
assert!(MediaFileType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileType::all_variants();
|
||||
assert_eq!(variants.len(), 20);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Audio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Image));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Video));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Bvh));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Fbx));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Glb));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Gltf));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Spz));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::SceneRon));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::SceneJson));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Pmd));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Vmd));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Pmx));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Csv));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Jpg));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Png));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Gif));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Mp4));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Wav));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Mp3));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(MediaFileType::all_variants().len(), MediaFileType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in MediaFileType::all_variants() {
|
||||
assert_eq!(variant, MediaFileType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, MediaFileType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, MediaFileType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in MediaFileType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
pub mod media_file_animation_type;
|
||||
pub mod media_file_class;
|
||||
pub mod media_file_engine_category;
|
||||
pub mod media_file_origin_category;
|
||||
// Moved to enums_db crate:
|
||||
// pub mod media_file_origin_model_type;
|
||||
pub mod media_file_origin_product_category;
|
||||
pub mod media_file_subtype;
|
||||
pub mod media_file_type;
|
||||
@@ -1,77 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `media_uploads` table in a `VARCHAR` field `media_source`.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub enum MediaUploadSource {
|
||||
/// Eg. browser javascript APIs to access the microphone, webcam, etc.
|
||||
#[serde(rename = "device_api")]
|
||||
DeviceApi,
|
||||
|
||||
/// Uploaded files from the filesystem
|
||||
#[serde(rename = "file")]
|
||||
File,
|
||||
|
||||
/// Unknown sources
|
||||
#[serde(rename = "unknown")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaUploadSource);
|
||||
impl_mysql_enum_coders!(MediaUploadSource);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaUploadSource {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::DeviceApi => "device_api",
|
||||
Self::File => "file",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"device_api" => Ok(Self::DeviceApi),
|
||||
"file" => Ok(Self::File),
|
||||
"unknown" => Ok(Self::Unknown),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_uploads::media_upload_source::MediaUploadSource;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaUploadSource::DeviceApi, "device_api");
|
||||
assert_serialization(MediaUploadSource::File, "file");
|
||||
assert_serialization(MediaUploadSource::Unknown, "unknown");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaUploadSource::DeviceApi.to_str(), "device_api");
|
||||
assert_eq!(MediaUploadSource::File.to_str(), "file");
|
||||
assert_eq!(MediaUploadSource::Unknown.to_str(), "unknown");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaUploadSource::from_str("device_api").unwrap(), MediaUploadSource::DeviceApi);
|
||||
assert_eq!(MediaUploadSource::from_str("file").unwrap(), MediaUploadSource::File);
|
||||
assert_eq!(MediaUploadSource::from_str("unknown").unwrap(), MediaUploadSource::Unknown);
|
||||
assert!(MediaUploadSource::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `media_uploads` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum MediaUploadType {
|
||||
/// Audio files: wav, mp3, etc.
|
||||
Audio,
|
||||
|
||||
/// Image files: png, jpeg, etc.
|
||||
Image,
|
||||
|
||||
/// Video files: mp4, etc.
|
||||
Video,
|
||||
|
||||
// Binary files: safetensors ... weights, etc.
|
||||
Binary,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(MediaUploadType);
|
||||
impl_mysql_enum_coders!(MediaUploadType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl MediaUploadType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Audio => "audio",
|
||||
Self::Image => "image",
|
||||
Self::Video => "video",
|
||||
Self::Binary => "binary",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"audio" => Ok(Self::Audio),
|
||||
"image" => Ok(Self::Image),
|
||||
"video" => Ok(Self::Video),
|
||||
"binary" => Ok(Self::Binary),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::media_uploads::media_upload_type::MediaUploadType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaUploadType::Audio, "audio");
|
||||
assert_serialization(MediaUploadType::Image, "image");
|
||||
assert_serialization(MediaUploadType::Video, "video");
|
||||
assert_serialization(MediaUploadType::Binary, "binary");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaUploadType::Audio.to_str(), "audio");
|
||||
assert_eq!(MediaUploadType::Image.to_str(), "image");
|
||||
assert_eq!(MediaUploadType::Video.to_str(), "video");
|
||||
assert_eq!(MediaUploadType::Binary.to_str(), "binary");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaUploadType::from_str("audio").unwrap(), MediaUploadType::Audio);
|
||||
assert_eq!(MediaUploadType::from_str("image").unwrap(), MediaUploadType::Image);
|
||||
assert_eq!(MediaUploadType::from_str("video").unwrap(), MediaUploadType::Video);
|
||||
assert_eq!(MediaUploadType::from_str("binary").unwrap(), MediaUploadType::Binary);
|
||||
assert!(MediaUploadType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod media_upload_type;
|
||||
pub mod media_upload_source;
|
||||
@@ -1,33 +0,0 @@
|
||||
// ===== MySql =====
|
||||
pub mod audit_logs;
|
||||
pub mod batch_generations;
|
||||
pub mod beta_keys;
|
||||
pub mod comments;
|
||||
pub mod email_sender_jobs;
|
||||
pub mod entity_stats;
|
||||
pub mod featured_items;
|
||||
pub mod generic_download_jobs;
|
||||
pub mod generic_inference_jobs;
|
||||
pub mod generic_synthetic_ids;
|
||||
pub mod media_files;
|
||||
pub mod media_uploads;
|
||||
pub mod model_categories;
|
||||
pub mod model_weights;
|
||||
pub mod prompt_context_items;
|
||||
pub mod prompts;
|
||||
pub mod tag_uses;
|
||||
pub mod trending_model_analytics;
|
||||
pub mod tts_models;
|
||||
pub mod usages;
|
||||
pub mod user_bookmarks;
|
||||
pub mod user_ratings;
|
||||
pub mod users;
|
||||
pub mod voice_conversion_models;
|
||||
pub mod voice_conversion_results;
|
||||
pub mod wallet_ledger_entries;
|
||||
pub mod zs_voices;
|
||||
|
||||
// ===== Sqlite =====
|
||||
pub mod tts_render_tasks;
|
||||
pub mod web_rendition_targets;
|
||||
pub mod web_scraping_targets;
|
||||
@@ -1 +0,0 @@
|
||||
pub mod model_type;
|
||||
@@ -1,65 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `model_categories` table in an `ENUM` field.
|
||||
/// (*WE WANT TO STOP USING ENUM FIELDS DUE TO MIGRATION ISSUES*)
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ModelType {
|
||||
Tts,
|
||||
W2l,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-16): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ModelType);
|
||||
impl_mysql_enum_coders!(ModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Tts => "tts",
|
||||
Self::W2l => "w2l",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"tts" => Ok(Self::Tts),
|
||||
"w2l" => Ok(Self::W2l),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::model_categories::model_type::ModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ModelType::Tts, "tts");
|
||||
assert_serialization(ModelType::W2l, "w2l");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(ModelType::Tts.to_str(), "tts");
|
||||
assert_eq!(ModelType::W2l.to_str(), "w2l");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(ModelType::from_str("tts").unwrap(), ModelType::Tts);
|
||||
assert_eq!(ModelType::from_str("w2l").unwrap(), ModelType::W2l);
|
||||
assert!(ModelType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Moved to enums_db crate:
|
||||
// pub mod weights_types;
|
||||
pub mod weights_category;
|
||||
pub mod weights_file_type;
|
||||
@@ -1,93 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum WeightsCategory {
|
||||
#[serde(rename = "image_generation")]
|
||||
ImageGeneration,
|
||||
#[serde(rename = "text_to_speech")]
|
||||
TextToSpeech,
|
||||
#[serde(rename = "vocoder")]
|
||||
Vocoder,
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversion,
|
||||
#[serde(rename = "workflow_config")]
|
||||
WorkflowConfig,
|
||||
}
|
||||
|
||||
impl WeightsCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ImageGeneration => "image_generation",
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::Vocoder => "vocoder",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::WorkflowConfig => "workflow_config",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"image_generation" => Ok(Self::ImageGeneration),
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"vocoder" => Ok(Self::Vocoder),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"workflow_config" => Ok(Self::WorkflowConfig),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::ImageGeneration,
|
||||
Self::TextToSpeech,
|
||||
Self::Vocoder,
|
||||
Self::VoiceConversion,
|
||||
Self::WorkflowConfig,
|
||||
])
|
||||
}
|
||||
}
|
||||
impl_enum_display_and_debug_using_to_str!(WeightsCategory);
|
||||
impl_mysql_enum_coders!(WeightsCategory);
|
||||
impl_mysql_from_row!(WeightsCategory);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(WeightsCategory::ImageGeneration.to_str(), "image_generation");
|
||||
assert_eq!(WeightsCategory::TextToSpeech.to_str(), "text_to_speech");
|
||||
assert_eq!(WeightsCategory::Vocoder.to_str(), "vocoder");
|
||||
assert_eq!(WeightsCategory::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(WeightsCategory::WorkflowConfig.to_str(), "workflow_config");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(WeightsCategory::from_str("image_generation").unwrap(), WeightsCategory::ImageGeneration);
|
||||
assert_eq!(WeightsCategory::from_str("text_to_speech").unwrap(), WeightsCategory::TextToSpeech);
|
||||
assert_eq!(WeightsCategory::from_str("vocoder").unwrap(), WeightsCategory::Vocoder);
|
||||
assert_eq!(WeightsCategory::from_str("voice_conversion").unwrap(), WeightsCategory::VoiceConversion);
|
||||
assert_eq!(WeightsCategory::from_str("workflow_config").unwrap(), WeightsCategory::WorkflowConfig);
|
||||
assert!(WeightsCategory::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_variants() {
|
||||
let variants = WeightsCategory::all_variants();
|
||||
assert_eq!(variants.len(), 5);
|
||||
assert!(variants.contains(&WeightsCategory::ImageGeneration));
|
||||
assert!(variants.contains(&WeightsCategory::TextToSpeech));
|
||||
assert!(variants.contains(&WeightsCategory::Vocoder));
|
||||
assert!(variants.contains(&WeightsCategory::VoiceConversion));
|
||||
assert!(variants.contains(&WeightsCategory::WorkflowConfig));
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
// TODO we will need to scan the checkpoints for malicious code. We can't just trust the file extension.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum WeightsFileType {
|
||||
#[serde(rename = "checkpoint")]
|
||||
Checkpoint,
|
||||
#[serde(rename = "safetensors")]
|
||||
SafeTensors,
|
||||
}
|
||||
|
||||
impl WeightsFileType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Checkpoint => "checkpoint",
|
||||
Self::SafeTensors => "safetensors",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"checkpoint" => Ok(Self::Checkpoint),
|
||||
"safetensors" => Ok(Self::SafeTensors),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::Checkpoint,
|
||||
Self::SafeTensors,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(WeightsFileType);
|
||||
impl_mysql_enum_coders!(WeightsFileType);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(WeightsFileType::Checkpoint.to_str(), "checkpoint");
|
||||
assert_eq!(WeightsFileType::SafeTensors.to_str(), "safetensors");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(WeightsFileType::from_str("checkpoint").unwrap(), WeightsFileType::Checkpoint);
|
||||
assert_eq!(WeightsFileType::from_str("safetensors").unwrap(), WeightsFileType::SafeTensors);
|
||||
assert!(WeightsFileType::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_variants() {
|
||||
let variants = WeightsFileType::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert!(variants.contains(&WeightsFileType::Checkpoint));
|
||||
assert!(variants.contains(&WeightsFileType::SafeTensors));
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod prompt_context_semantic_type;
|
||||
-213
@@ -1,213 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/*
|
||||
Current DB values - this is in conflict with API serializations. Need to fix!
|
||||
imgref
|
||||
imgsrc
|
||||
imgmask
|
||||
vid_start_frame
|
||||
vid_end_frame
|
||||
vidref
|
||||
*/
|
||||
|
||||
/// Used in the `prompt_context_items` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PromptContextSemanticType {
|
||||
/// Image-to-Video starting frame
|
||||
VidStartFrame,
|
||||
|
||||
/// Image-to-Video ending frame
|
||||
VidEndFrame,
|
||||
|
||||
/// Reference image for video generation (e.g. Seedance "vidref" mode)
|
||||
VidRef,
|
||||
|
||||
/// Source image, eg. for inpainting.
|
||||
Imgsrc,
|
||||
|
||||
/// Image mask, eg. for inpainting.
|
||||
Imgmask,
|
||||
|
||||
/// Standard image reference without a semantic type (e.g. Sora/ChatGPT 4o/gpt-image-1)
|
||||
Imgref,
|
||||
|
||||
ImgrefCharacter,
|
||||
ImgrefStyle,
|
||||
ImgrefBg,
|
||||
|
||||
/// Audio reference (e.g. for audio-to-video generation)
|
||||
Audioref,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(PromptContextSemanticType);
|
||||
impl_mysql_enum_coders!(PromptContextSemanticType);
|
||||
impl_mysql_from_row!(PromptContextSemanticType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl PromptContextSemanticType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::VidStartFrame => "vid_start_frame",
|
||||
Self::VidEndFrame => "vid_end_frame",
|
||||
Self::VidRef => "vidref",
|
||||
Self::Imgsrc => "imgsrc",
|
||||
Self::Imgmask => "imgmask",
|
||||
Self::Imgref => "imgref",
|
||||
Self::ImgrefCharacter => "imgref_character",
|
||||
Self::ImgrefStyle => "imgref_style",
|
||||
Self::ImgrefBg => "imgref_bg",
|
||||
Self::Audioref => "audioref",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"vid_start_frame" => Ok(Self::VidStartFrame),
|
||||
"vid_end_frame" => Ok(Self::VidEndFrame),
|
||||
"vidref" => Ok(Self::VidRef),
|
||||
"imgsrc" => Ok(Self::Imgsrc),
|
||||
"imgmask" => Ok(Self::Imgmask),
|
||||
"imgref" => Ok(Self::Imgref),
|
||||
"imgref_character" => Ok(Self::ImgrefCharacter),
|
||||
"imgref_style" => Ok(Self::ImgrefStyle),
|
||||
"imgref_bg" => Ok(Self::ImgrefBg),
|
||||
"audioref" => Ok(Self::Audioref),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::VidStartFrame,
|
||||
Self::VidEndFrame,
|
||||
Self::VidRef,
|
||||
Self::Imgsrc,
|
||||
Self::Imgmask,
|
||||
Self::Imgref,
|
||||
Self::ImgrefCharacter,
|
||||
Self::ImgrefStyle,
|
||||
Self::ImgrefBg,
|
||||
Self::Audioref,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::prompt_context_items::prompt_context_semantic_type::PromptContextSemanticType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(PromptContextSemanticType::VidStartFrame, "vid_start_frame");
|
||||
assert_serialization(PromptContextSemanticType::VidEndFrame, "vid_end_frame");
|
||||
assert_serialization(PromptContextSemanticType::VidRef, "vidref");
|
||||
assert_serialization(PromptContextSemanticType::Imgsrc, "imgsrc");
|
||||
assert_serialization(PromptContextSemanticType::Imgmask, "imgmask");
|
||||
assert_serialization(PromptContextSemanticType::Imgref, "imgref");
|
||||
assert_serialization(PromptContextSemanticType::ImgrefCharacter, "imgref_character");
|
||||
assert_serialization(PromptContextSemanticType::ImgrefStyle, "imgref_style");
|
||||
assert_serialization(PromptContextSemanticType::ImgrefBg, "imgref_bg");
|
||||
assert_serialization(PromptContextSemanticType::Audioref, "audioref");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(PromptContextSemanticType::VidStartFrame.to_str(), "vid_start_frame");
|
||||
assert_eq!(PromptContextSemanticType::VidEndFrame.to_str(), "vid_end_frame");
|
||||
assert_eq!(PromptContextSemanticType::VidRef.to_str(), "vidref");
|
||||
assert_eq!(PromptContextSemanticType::Imgsrc.to_str(), "imgsrc");
|
||||
assert_eq!(PromptContextSemanticType::Imgmask.to_str(), "imgmask");
|
||||
assert_eq!(PromptContextSemanticType::Imgref.to_str(), "imgref");
|
||||
assert_eq!(PromptContextSemanticType::ImgrefCharacter.to_str(), "imgref_character");
|
||||
assert_eq!(PromptContextSemanticType::ImgrefStyle.to_str(), "imgref_style");
|
||||
assert_eq!(PromptContextSemanticType::ImgrefBg.to_str(), "imgref_bg");
|
||||
assert_eq!(PromptContextSemanticType::Audioref.to_str(), "audioref");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(PromptContextSemanticType::from_str("vid_start_frame").unwrap(), PromptContextSemanticType::VidStartFrame);
|
||||
assert_eq!(PromptContextSemanticType::from_str("vid_end_frame").unwrap(), PromptContextSemanticType::VidEndFrame);
|
||||
assert_eq!(PromptContextSemanticType::from_str("vidref").unwrap(), PromptContextSemanticType::VidRef);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgsrc").unwrap(), PromptContextSemanticType::Imgsrc);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgmask").unwrap(), PromptContextSemanticType::Imgmask);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgref").unwrap(), PromptContextSemanticType::Imgref);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgref_character").unwrap(), PromptContextSemanticType::ImgrefCharacter);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgref_style").unwrap(), PromptContextSemanticType::ImgrefStyle);
|
||||
assert_eq!(PromptContextSemanticType::from_str("imgref_bg").unwrap(), PromptContextSemanticType::ImgrefBg);
|
||||
assert_eq!(PromptContextSemanticType::from_str("audioref").unwrap(), PromptContextSemanticType::Audioref);
|
||||
assert!(PromptContextSemanticType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = PromptContextSemanticType::all_variants();
|
||||
assert_eq!(variants.len(), 10);
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::VidStartFrame));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::VidEndFrame));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::VidRef));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::Imgsrc));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::Imgmask));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::Imgref));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::ImgrefCharacter));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::ImgrefStyle));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::ImgrefBg));
|
||||
assert_eq!(variants.pop_first(), Some(PromptContextSemanticType::Audioref));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(PromptContextSemanticType::all_variants().len(), PromptContextSemanticType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in PromptContextSemanticType::all_variants() {
|
||||
assert_eq!(variant, PromptContextSemanticType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, PromptContextSemanticType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, PromptContextSemanticType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in PromptContextSemanticType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod prompt_type;
|
||||
@@ -1,140 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `prompts` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PromptType {
|
||||
/// Artcraft (App)
|
||||
ArtcraftApp,
|
||||
|
||||
/// Stable diffusion
|
||||
#[deprecated]
|
||||
StableDiffusion,
|
||||
|
||||
/// Comfy UI
|
||||
#[deprecated]
|
||||
ComfyUi,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(PromptType);
|
||||
impl_mysql_enum_coders!(PromptType);
|
||||
impl_mysql_from_row!(PromptType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl PromptType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ArtcraftApp => "artcraft_app",
|
||||
Self::StableDiffusion => "stable_diffusion",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"artcraft_app" => Ok(Self::ArtcraftApp),
|
||||
"stable_diffusion" => Ok(Self::StableDiffusion),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ArtcraftApp,
|
||||
Self::StableDiffusion,
|
||||
Self::ComfyUi,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::prompts::prompt_type::PromptType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(PromptType::ArtcraftApp, "artcraft_app");
|
||||
assert_serialization(PromptType::StableDiffusion, "stable_diffusion");
|
||||
assert_serialization(PromptType::ComfyUi, "comfy_ui");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(PromptType::ArtcraftApp.to_str(), "artcraft_app");
|
||||
assert_eq!(PromptType::StableDiffusion.to_str(), "stable_diffusion");
|
||||
assert_eq!(PromptType::ComfyUi.to_str(), "comfy_ui");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(PromptType::from_str("artcraft_app").unwrap(), PromptType::ArtcraftApp);
|
||||
assert_eq!(PromptType::from_str("stable_diffusion").unwrap(), PromptType::StableDiffusion);
|
||||
assert_eq!(PromptType::from_str("comfy_ui").unwrap(), PromptType::ComfyUi);
|
||||
assert!(PromptType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = PromptType::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert_eq!(variants.pop_first(), Some(PromptType::ArtcraftApp));
|
||||
assert_eq!(variants.pop_first(), Some(PromptType::StableDiffusion));
|
||||
assert_eq!(variants.pop_first(), Some(PromptType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(PromptType::all_variants().len(), PromptType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in PromptType::all_variants() {
|
||||
assert_eq!(variant, PromptType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, PromptType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, PromptType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in PromptType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod tag_use_entity_type;
|
||||
@@ -1,127 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `tag_uses` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
|
||||
pub enum TagUseEntityType {
|
||||
/// Media files
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// Model weights
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(TagUseEntityType);
|
||||
impl_mysql_enum_coders!(TagUseEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl TagUseEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::MediaFile,
|
||||
Self::ModelWeight,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::test_helpers::assert_serialization;
|
||||
use crate::by_table::tag_uses::tag_use_entity_type::TagUseEntityType;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(TagUseEntityType::MediaFile, "media_file");
|
||||
assert_serialization(TagUseEntityType::ModelWeight, "model_weight");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(TagUseEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(TagUseEntityType::ModelWeight.to_str(), "model_weight");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(TagUseEntityType::from_str("media_file").unwrap(), TagUseEntityType::MediaFile);
|
||||
assert_eq!(TagUseEntityType::from_str("model_weight").unwrap(), TagUseEntityType::ModelWeight);
|
||||
assert!(TagUseEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = TagUseEntityType::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert_eq!(variants.pop_first(), Some(TagUseEntityType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(TagUseEntityType::ModelWeight));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(TagUseEntityType::all_variants().len(), TagUseEntityType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in TagUseEntityType::all_variants() {
|
||||
assert_eq!(variant, TagUseEntityType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, TagUseEntityType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, TagUseEntityType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in TagUseEntityType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod model_type;
|
||||
pub mod window_name;
|
||||
@@ -1,62 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `trending_model_analytics` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ModelType {
|
||||
/// TTS models
|
||||
Tts,
|
||||
|
||||
// NB: It's assumed we'll use this same system to track
|
||||
// trending VC models too, so the next type would be "VC".
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ModelType);
|
||||
impl_mysql_enum_coders!(ModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Tts => "tts",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"tts" => Ok(Self::Tts),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::trending_model_analytics::model_type::ModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ModelType::Tts, "tts");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(ModelType::Tts.to_str(), "tts");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(ModelType::from_str("tts").unwrap(), ModelType::Tts);
|
||||
assert!(ModelType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `window_name` table in a `VARCHAR` field.
|
||||
///
|
||||
/// Contrary to most of this crate and unlike most "enum"-types
|
||||
/// that are inflexible, new window names can be added/removed
|
||||
/// without breaking too much.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum WindowName {
|
||||
/// Analytics over the last three hours
|
||||
#[serde(rename = "last_3_hours")]
|
||||
Last3Hours,
|
||||
|
||||
/// Analytics over the last three hours
|
||||
#[serde(rename = "last_3_days")]
|
||||
Last3Days,
|
||||
|
||||
/// Analytics over all historical records
|
||||
#[serde(rename = "all_time")]
|
||||
AllTime,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(WindowName);
|
||||
impl_mysql_enum_coders!(WindowName);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl WindowName {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Last3Hours => "last_3_hours",
|
||||
Self::Last3Days => "last_3_days",
|
||||
Self::AllTime => "all_time",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"last_3_hours" => Ok(Self::Last3Hours),
|
||||
"last_3_days" => Ok(Self::Last3Days),
|
||||
"all_time" => Ok(Self::AllTime),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::trending_model_analytics::window_name::WindowName;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(WindowName::Last3Hours, "last_3_hours");
|
||||
assert_serialization(WindowName::Last3Days, "last_3_days");
|
||||
assert_serialization(WindowName::AllTime, "all_time");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(WindowName::Last3Hours.to_str(), "last_3_hours");
|
||||
assert_eq!(WindowName::Last3Days.to_str(), "last_3_days");
|
||||
assert_eq!(WindowName::AllTime.to_str(), "all_time");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(WindowName::from_str("last_3_hours").unwrap(), WindowName::Last3Hours);
|
||||
assert_eq!(WindowName::from_str("last_3_days").unwrap(), WindowName::Last3Days);
|
||||
assert_eq!(WindowName::from_str("all_time").unwrap(), WindowName::AllTime);
|
||||
assert!(WindowName::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod tts_model_type;
|
||||
@@ -1,67 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `tts_models` table in an `ENUM` field.
|
||||
/// -- Furthermore -- not all enum values are represented !!
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub enum TtsModelType {
|
||||
#[serde(rename = "tacotron2")]
|
||||
Tacotron2,
|
||||
|
||||
#[serde(rename = "vits")]
|
||||
Vits,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-04-03): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(TtsModelType);
|
||||
impl_mysql_enum_coders!(TtsModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl TtsModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Tacotron2 => "tacotron2",
|
||||
Self::Vits => "vits",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"tacotron2" => Ok(Self::Tacotron2),
|
||||
"vits" => Ok(Self::Vits),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::tts_models::tts_model_type::TtsModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(TtsModelType::Tacotron2, "tacotron2");
|
||||
assert_serialization(TtsModelType::Vits, "vits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(TtsModelType::Tacotron2.to_str(), "tacotron2");
|
||||
assert_eq!(TtsModelType::Vits.to_str(), "vits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(TtsModelType::from_str("tacotron2").unwrap(), TtsModelType::Tacotron2);
|
||||
assert_eq!(TtsModelType::from_str("vits").unwrap(), TtsModelType::Vits);
|
||||
assert!(TtsModelType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod tts_render_status;
|
||||
@@ -1,105 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the SqLite `tts_render_tasks` table in a `TEXT` field named `tts_render_status`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum TtsRenderStatus {
|
||||
#[serde(rename = "new")]
|
||||
New,
|
||||
|
||||
// TODO: Added to fix a big. This whole enum should die.
|
||||
#[serde(rename = "processing")]
|
||||
Processing,
|
||||
|
||||
#[serde(rename = "skipped")]
|
||||
Skipped,
|
||||
|
||||
#[serde(rename = "failed")]
|
||||
Failed,
|
||||
|
||||
#[serde(rename = "permanently_failed")]
|
||||
PermanentlyFailed,
|
||||
|
||||
#[serde(rename = "success")]
|
||||
Success,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs Sqlite integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(TtsRenderStatus);
|
||||
impl_sqlite_enum_coders!(TtsRenderStatus);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl TtsRenderStatus {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::New => "new",
|
||||
Self::Processing => "processing",
|
||||
Self::Skipped => "skipped",
|
||||
Self::Failed => "failed",
|
||||
Self::PermanentlyFailed => "permanently_failed",
|
||||
Self::Success => "success",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"new" => Ok(Self::New),
|
||||
"processing" => Ok(Self::Processing),
|
||||
"skipped" => Ok(Self::Skipped),
|
||||
"failed" => Ok(Self::Failed),
|
||||
"permanently_failed" => Ok(Self::PermanentlyFailed),
|
||||
"success" => Ok(Self::Success),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::tts_render_tasks::tts_render_status::TtsRenderStatus;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(TtsRenderStatus::New, "new");
|
||||
assert_serialization(TtsRenderStatus::Processing, "processing");
|
||||
assert_serialization(TtsRenderStatus::Skipped, "skipped");
|
||||
assert_serialization(TtsRenderStatus::Failed, "failed");
|
||||
assert_serialization(TtsRenderStatus::PermanentlyFailed, "permanently_failed");
|
||||
assert_serialization(TtsRenderStatus::Success, "success");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(TtsRenderStatus::New.to_str(), "new");
|
||||
assert_eq!(TtsRenderStatus::Processing.to_str(), "processing");
|
||||
assert_eq!(TtsRenderStatus::Skipped.to_str(), "skipped");
|
||||
assert_eq!(TtsRenderStatus::Failed.to_str(), "failed");
|
||||
assert_eq!(TtsRenderStatus::PermanentlyFailed.to_str(), "permanently_failed");
|
||||
assert_eq!(TtsRenderStatus::Success.to_str(), "success");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(TtsRenderStatus::from_str("new").unwrap(), TtsRenderStatus::New);
|
||||
assert_eq!(TtsRenderStatus::from_str("processing").unwrap(), TtsRenderStatus::Processing);
|
||||
assert_eq!(TtsRenderStatus::from_str("skipped").unwrap(), TtsRenderStatus::Skipped);
|
||||
assert_eq!(TtsRenderStatus::from_str("failed").unwrap(), TtsRenderStatus::Failed);
|
||||
assert_eq!(TtsRenderStatus::from_str("permanently_failed").unwrap(), TtsRenderStatus::PermanentlyFailed);
|
||||
assert_eq!(TtsRenderStatus::from_str("success").unwrap(), TtsRenderStatus::Success);
|
||||
assert!(TtsRenderStatus::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod usages_type;
|
||||
@@ -1,128 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `usages` table in a `VARCHAR(16)` field. (Two fields!)
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UsagesType {
|
||||
/// Represents a foreign key link against a model_weights record
|
||||
ModelWeight,
|
||||
|
||||
/// Represents a foreign key link against a media_files record
|
||||
MediaFile,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UsagesType);
|
||||
impl_mysql_enum_coders!(UsagesType);
|
||||
impl_mysql_from_row!(UsagesType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UsagesType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::MediaFile => "media_file",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ModelWeight,
|
||||
Self::MediaFile,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::usages::usages_type::UsagesType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UsagesType::ModelWeight, "model_weight");
|
||||
assert_serialization(UsagesType::MediaFile, "media_file");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(UsagesType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(UsagesType::MediaFile.to_str(), "media_file");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(UsagesType::from_str("model_weight").unwrap(), UsagesType::ModelWeight);
|
||||
assert_eq!(UsagesType::from_str("media_file").unwrap(), UsagesType::MediaFile);
|
||||
assert!(UsagesType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = UsagesType::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert_eq!(variants.pop_first(), Some(UsagesType::ModelWeight));
|
||||
assert_eq!(variants.pop_first(), Some(UsagesType::MediaFile));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(UsagesType::all_variants().len(), UsagesType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in UsagesType::all_variants() {
|
||||
assert_eq!(variant, UsagesType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, UsagesType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, UsagesType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in UsagesType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod user_bookmark_entity_type;
|
||||
@@ -1,139 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)]
|
||||
pub enum UserBookmarkEntityType {
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
|
||||
/// TTS model (architecture does not matter)
|
||||
#[serde(rename = "tts_model")]
|
||||
TtsModel,
|
||||
|
||||
/// TTS result (architecture does not matter)
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// W2L template
|
||||
#[serde(rename = "w2l_template")]
|
||||
W2lTemplate,
|
||||
|
||||
/// W2L result
|
||||
#[serde(rename = "w2l_result")]
|
||||
W2lResult,
|
||||
|
||||
/// MediaFile
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// ModelWeight (the new way to store models)
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
|
||||
/// VoiceConversionModel
|
||||
#[serde(rename = "voice_conversion_model")]
|
||||
VoiceConversionModel,
|
||||
|
||||
/// ZsVoice
|
||||
#[serde(rename = "zs_voice")]
|
||||
ZsVoice,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserBookmarkEntityType);
|
||||
impl_mysql_enum_coders!(UserBookmarkEntityType);
|
||||
impl_mysql_from_row!(UserBookmarkEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserBookmarkEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::User => "user",
|
||||
Self::TtsModel => "tts_model",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::W2lTemplate => "w2l_template",
|
||||
Self::W2lResult => "w2l_result",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::VoiceConversionModel => "voice_conversion_model",
|
||||
Self::ZsVoice => "zs_voice",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"user" => Ok(Self::User),
|
||||
"tts_model" => Ok(Self::TtsModel),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"w2l_template" => Ok(Self::W2lTemplate),
|
||||
"w2l_result" => Ok(Self::W2lResult),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"voice_conversion_model" => Ok(Self::VoiceConversionModel),
|
||||
"zs_voice" => Ok(Self::ZsVoice),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserBookmarkEntityType::User, "user");
|
||||
assert_serialization(UserBookmarkEntityType::TtsModel, "tts_model");
|
||||
assert_serialization(UserBookmarkEntityType::TtsResult, "tts_result");
|
||||
assert_serialization(UserBookmarkEntityType::W2lTemplate, "w2l_template");
|
||||
assert_serialization(UserBookmarkEntityType::W2lResult, "w2l_result");
|
||||
assert_serialization(UserBookmarkEntityType::MediaFile, "media_file");
|
||||
assert_serialization(UserBookmarkEntityType::ModelWeight, "model_weight");
|
||||
assert_serialization(UserBookmarkEntityType::VoiceConversionModel, "voice_conversion_model");
|
||||
assert_serialization(UserBookmarkEntityType::ZsVoice, "zs_voice");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(UserBookmarkEntityType::User.to_str(), "user");
|
||||
assert_eq!(UserBookmarkEntityType::TtsModel.to_str(), "tts_model");
|
||||
assert_eq!(UserBookmarkEntityType::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(UserBookmarkEntityType::W2lTemplate.to_str(), "w2l_template");
|
||||
assert_eq!(UserBookmarkEntityType::W2lResult.to_str(), "w2l_result");
|
||||
assert_eq!(UserBookmarkEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(UserBookmarkEntityType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(UserBookmarkEntityType::VoiceConversionModel.to_str(), "voice_conversion_model");
|
||||
assert_eq!(UserBookmarkEntityType::ZsVoice.to_str(), "zs_voice");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(UserBookmarkEntityType::from_str("user").unwrap(), UserBookmarkEntityType::User);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("tts_model").unwrap(), UserBookmarkEntityType::TtsModel);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("tts_result").unwrap(), UserBookmarkEntityType::TtsResult);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("w2l_template").unwrap(), UserBookmarkEntityType::W2lTemplate);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("w2l_result").unwrap(), UserBookmarkEntityType::W2lResult);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("media_file").unwrap(), UserBookmarkEntityType::MediaFile);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("model_weight").unwrap(), UserBookmarkEntityType::ModelWeight);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("voice_conversion_model").unwrap(), UserBookmarkEntityType::VoiceConversionModel);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("zs_voice").unwrap(), UserBookmarkEntityType::ZsVoice);
|
||||
assert!(UserBookmarkEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `user_ratings` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)]
|
||||
pub enum UserRatingEntityType {
|
||||
/// Media files (inference results, uploads, etc.)
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// Model weights (modern, polymorphic, type agnostic)
|
||||
#[serde(rename = "model_weight")]
|
||||
ModelWeight,
|
||||
|
||||
/// TTS model (architecture does not matter)
|
||||
#[serde(rename = "tts_model")]
|
||||
TtsModel,
|
||||
|
||||
/// TTS result (architecture does not matter)
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// W2L template
|
||||
#[serde(rename = "w2l_template")]
|
||||
W2lTemplate,
|
||||
|
||||
/// W2L result
|
||||
#[serde(rename = "w2l_result")]
|
||||
W2lResult,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserRatingEntityType);
|
||||
impl_mysql_enum_coders!(UserRatingEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserRatingEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::ModelWeight => "model_weight",
|
||||
Self::TtsModel => "tts_model",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::W2lTemplate => "w2l_template",
|
||||
Self::W2lResult => "w2l_result",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"model_weight" => Ok(Self::ModelWeight),
|
||||
"tts_model" => Ok(Self::TtsModel),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"w2l_template" => Ok(Self::W2lTemplate),
|
||||
"w2l_result" => Ok(Self::W2lResult),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::user_ratings::entity_type::UserRatingEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserRatingEntityType::MediaFile, "media_file");
|
||||
assert_serialization(UserRatingEntityType::ModelWeight, "model_weight");
|
||||
assert_serialization(UserRatingEntityType::TtsModel, "tts_model");
|
||||
assert_serialization(UserRatingEntityType::TtsResult, "tts_result");
|
||||
assert_serialization(UserRatingEntityType::W2lTemplate, "w2l_template");
|
||||
assert_serialization(UserRatingEntityType::W2lResult, "w2l_result");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(UserRatingEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(UserRatingEntityType::ModelWeight.to_str(), "model_weight");
|
||||
assert_eq!(UserRatingEntityType::TtsModel.to_str(), "tts_model");
|
||||
assert_eq!(UserRatingEntityType::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(UserRatingEntityType::W2lTemplate.to_str(), "w2l_template");
|
||||
assert_eq!(UserRatingEntityType::W2lResult.to_str(), "w2l_result");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(UserRatingEntityType::from_str("media_file").unwrap(), UserRatingEntityType::MediaFile);
|
||||
assert_eq!(UserRatingEntityType::from_str("model_weight").unwrap(), UserRatingEntityType::ModelWeight);
|
||||
assert_eq!(UserRatingEntityType::from_str("tts_model").unwrap(), UserRatingEntityType::TtsModel);
|
||||
assert_eq!(UserRatingEntityType::from_str("tts_result").unwrap(), UserRatingEntityType::TtsResult);
|
||||
assert_eq!(UserRatingEntityType::from_str("w2l_template").unwrap(), UserRatingEntityType::W2lTemplate);
|
||||
assert_eq!(UserRatingEntityType::from_str("w2l_result").unwrap(), UserRatingEntityType::W2lResult);
|
||||
assert!(UserRatingEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod entity_type;
|
||||
pub mod rating_value;
|
||||
@@ -1,163 +0,0 @@
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// UserRatingValue
|
||||
///
|
||||
/// - Used in the `user_ratings` table as an `ENUM` field named `rating_type`.
|
||||
/// - Used in the HTTP API.
|
||||
///
|
||||
/// To use this in a query, the query must have type annotations.
|
||||
/// See: https://www.gitmemory.com/issue/launchbadge/sqlx/1241/847154375
|
||||
/// eg. preferred_tts_result_visibility as `rating_type: enums::by_table::user_ratings::rating_type::UserRatingValue`
|
||||
///
|
||||
/// See also: https://docs.rs/sqlx/0.4.0-beta.1/sqlx/trait.Type.html
|
||||
///
|
||||
/// *DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY!*
|
||||
///
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
|
||||
#[cfg_attr(feature = "database", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "database", sqlx(rename_all = "lowercase"))]
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum UserRatingValue {
|
||||
/// This is considered a ratings "soft deletion" and does not count towards a total score.
|
||||
/// This is the default rating.
|
||||
Neutral,
|
||||
/// This is a positive vote / upvote / like.
|
||||
/// They are available to non-logged-in users as long as they have the URL.
|
||||
Positive,
|
||||
/// This is a negative vote / downvote / dislike.
|
||||
Negative,
|
||||
}
|
||||
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(UserRatingValue);
|
||||
|
||||
impl Default for UserRatingValue {
|
||||
fn default() -> Self { Self::Neutral }
|
||||
}
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserRatingValue {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Neutral => "neutral",
|
||||
Self::Positive => "positive",
|
||||
Self::Negative => "negative",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"neutral" => Ok(Self::Neutral),
|
||||
"positive" => Ok(Self::Positive),
|
||||
"negative" => Ok(Self::Negative),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::user_ratings::rating_value::UserRatingValue;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserRatingValue::Neutral, "neutral");
|
||||
assert_serialization(UserRatingValue::Positive, "positive");
|
||||
assert_serialization(UserRatingValue::Negative, "negative");
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(UserRatingValue::Neutral.to_str(), "neutral");
|
||||
assert_eq!(UserRatingValue::Positive.to_str(), "positive");
|
||||
assert_eq!(UserRatingValue::Negative.to_str(), "negative");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(UserRatingValue::from_str("neutral").unwrap(), UserRatingValue::Neutral);
|
||||
assert_eq!(UserRatingValue::from_str("positive").unwrap(), UserRatingValue::Positive);
|
||||
assert_eq!(UserRatingValue::from_str("negative").unwrap(), UserRatingValue::Negative);
|
||||
assert!(UserRatingValue::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod traits {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
assert_eq!(UserRatingValue::default(), UserRatingValue::Neutral);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display() {
|
||||
let visibility = UserRatingValue::Positive;
|
||||
assert_eq!(format!("{}", visibility), "positive".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug() {
|
||||
let visibility = UserRatingValue::Negative;
|
||||
assert_eq!(format!("{:?}", visibility), "negative".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct CompositeType {
|
||||
visibility: UserRatingValue,
|
||||
string: String,
|
||||
}
|
||||
|
||||
mod serde_serialization {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn serialize() {
|
||||
let expected = "\"positive\"".to_string(); // NB: Quoted
|
||||
|
||||
assert_eq!(expected, serde_json::to_string(&UserRatingValue::Positive).unwrap());
|
||||
|
||||
// Just to show this serializes the same as a string
|
||||
assert_eq!(expected, serde_json::to_string("positive").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_serialize() {
|
||||
let value = CompositeType { visibility: UserRatingValue::Negative, string: "bar".to_string() };
|
||||
let expected = r#"{"visibility":"negative","string":"bar"}"#.to_string();
|
||||
assert_eq!(expected, serde_json::to_string(&value).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
mod serde_deserialization {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialize() {
|
||||
let payload = "\"positive\""; // NB: Quoted
|
||||
let value: UserRatingValue = serde_json::from_str(payload).unwrap();
|
||||
assert_eq!(value, UserRatingValue::Positive);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_deserialize() {
|
||||
let payload = r#"{"visibility":"neutral","string":"bar"}"#.to_string();
|
||||
let expected = CompositeType {
|
||||
visibility: UserRatingValue::Neutral,
|
||||
string: "bar".to_string(),
|
||||
};
|
||||
|
||||
assert_eq!(expected, serde_json::from_str::<CompositeType>(&payload).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod user_feature_flag;
|
||||
pub mod user_signup_method;
|
||||
pub mod user_signup_source;
|
||||
@@ -1,144 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `users` table in a `VARCHAR` field (stored as comma separated set).
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserFeatureFlag {
|
||||
/// Grants a user the ability to list media
|
||||
/// (For now, it's hidden until we get an NSFW filter.)
|
||||
ExploreMedia,
|
||||
|
||||
/// Access to studio features
|
||||
Studio,
|
||||
|
||||
/// Whether users are allowed to upload 3D models
|
||||
#[serde(rename = "upload_3d")]
|
||||
Upload3d,
|
||||
|
||||
/// Access to video style transfer
|
||||
VideoStyleTransfer,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserFeatureFlag);
|
||||
impl_mysql_enum_coders!(UserFeatureFlag);
|
||||
impl_mysql_from_row!(UserFeatureFlag);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserFeatureFlag {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ExploreMedia => "explore_media",
|
||||
Self::Studio => "studio",
|
||||
Self::Upload3d => "upload_3d",
|
||||
Self::VideoStyleTransfer => "video_style_transfer",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"explore_media" => Ok(Self::ExploreMedia),
|
||||
"studio" => Ok(Self::Studio),
|
||||
"upload_3d" => Ok(Self::Upload3d),
|
||||
"video_style_transfer" => Ok(Self::VideoStyleTransfer),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ExploreMedia,
|
||||
Self::Studio,
|
||||
Self::Upload3d,
|
||||
Self::VideoStyleTransfer,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserFeatureFlag::ExploreMedia, "explore_media");
|
||||
assert_serialization(UserFeatureFlag::Studio, "studio");
|
||||
assert_serialization(UserFeatureFlag::Upload3d, "upload_3d");
|
||||
assert_serialization(UserFeatureFlag::VideoStyleTransfer, "video_style_transfer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(UserFeatureFlag::ExploreMedia.to_str(), "explore_media");
|
||||
assert_eq!(UserFeatureFlag::Studio.to_str(), "studio");
|
||||
assert_eq!(UserFeatureFlag::Upload3d.to_str(), "upload_3d");
|
||||
assert_eq!(UserFeatureFlag::VideoStyleTransfer.to_str(), "video_style_transfer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(UserFeatureFlag::from_str("explore_media").unwrap(), UserFeatureFlag::ExploreMedia);
|
||||
assert_eq!(UserFeatureFlag::from_str("studio").unwrap(), UserFeatureFlag::Studio);
|
||||
assert_eq!(UserFeatureFlag::from_str("upload_3d").unwrap(), UserFeatureFlag::Upload3d);
|
||||
assert_eq!(UserFeatureFlag::from_str("video_style_transfer").unwrap(), UserFeatureFlag::VideoStyleTransfer);
|
||||
assert!(UserFeatureFlag::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = UserFeatureFlag::all_variants();
|
||||
assert_eq!(variants.len(), 4);
|
||||
assert_eq!(variants.pop_first(), Some(UserFeatureFlag::ExploreMedia));
|
||||
assert_eq!(variants.pop_first(), Some(UserFeatureFlag::Studio));
|
||||
assert_eq!(variants.pop_first(), Some(UserFeatureFlag::Upload3d));
|
||||
assert_eq!(variants.pop_first(), Some(UserFeatureFlag::VideoStyleTransfer));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(UserFeatureFlag::all_variants().len(), UserFeatureFlag::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in UserFeatureFlag::all_variants() {
|
||||
assert_eq!(variant, UserFeatureFlag::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, UserFeatureFlag::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, UserFeatureFlag::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 32;
|
||||
for variant in UserFeatureFlag::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `users` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserSignupMethod {
|
||||
/// Email + Password
|
||||
EmailPassword,
|
||||
|
||||
/// "Sign in With Google" SSO
|
||||
GoogleSignIn,
|
||||
|
||||
/// Stripe Checkout flow, where we provision user accounts for users with a
|
||||
/// synthetic/fake email address and no password. After checkout completes,
|
||||
/// the user gets a real email and password - or the user can set them.
|
||||
StripeCheckout,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserSignupMethod);
|
||||
impl_mysql_enum_coders!(UserSignupMethod);
|
||||
impl_mysql_from_row!(UserSignupMethod);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserSignupMethod {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::EmailPassword => "email_password",
|
||||
Self::GoogleSignIn=> "google_sign_in",
|
||||
Self::StripeCheckout => "stripe_checkout",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"email_password" => Ok(Self::EmailPassword),
|
||||
"google_sign_in" => Ok(Self::GoogleSignIn),
|
||||
"stripe_checkout" => Ok(Self::StripeCheckout),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::EmailPassword,
|
||||
Self::GoogleSignIn,
|
||||
Self::StripeCheckout,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::users::user_signup_method::UserSignupMethod;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserSignupMethod::EmailPassword, "email_password");
|
||||
assert_serialization(UserSignupMethod::GoogleSignIn, "google_sign_in");
|
||||
assert_serialization(UserSignupMethod::StripeCheckout, "stripe_checkout");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(UserSignupMethod::EmailPassword.to_str(), "email_password");
|
||||
assert_eq!(UserSignupMethod::GoogleSignIn.to_str(), "google_sign_in");
|
||||
assert_eq!(UserSignupMethod::StripeCheckout.to_str(), "stripe_checkout");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(UserSignupMethod::from_str("email_password").unwrap(), UserSignupMethod::EmailPassword);
|
||||
assert_eq!(UserSignupMethod::from_str("google_sign_in").unwrap(), UserSignupMethod::GoogleSignIn);
|
||||
assert_eq!(UserSignupMethod::from_str("stripe_checkout").unwrap(), UserSignupMethod::StripeCheckout);
|
||||
assert!(UserSignupMethod::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = UserSignupMethod::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupMethod::EmailPassword));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupMethod::GoogleSignIn));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupMethod::StripeCheckout));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(UserSignupMethod::all_variants().len(), UserSignupMethod::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in UserSignupMethod::all_variants() {
|
||||
assert_eq!(variant, UserSignupMethod::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, UserSignupMethod::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, UserSignupMethod::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in UserSignupMethod::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `users` table in a `VARCHAR(255)` (which should be a `VARCHAR(16)`) field, `maybe_source`.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserSignupSource {
|
||||
#[deprecated(since = "2026-01-30", note = "Use other Artcraft* enum variants instead")]
|
||||
#[serde(rename = "artcraft")]
|
||||
ArtCraft,
|
||||
|
||||
/// ArtCraft Tauri App Onboard Flow
|
||||
#[serde(rename = "artcraft_app")]
|
||||
ArtCraftApp,
|
||||
|
||||
/// artcraft.ai normal onboard flow
|
||||
#[serde(rename = "artcraft_ai_web")]
|
||||
ArtCraftAiWeb,
|
||||
|
||||
/// artcraft.ai stripe checkout flow
|
||||
#[serde(rename = "artcraft_ai_s")]
|
||||
ArtCraftAiStripe,
|
||||
|
||||
/// getartcraft.com normal onboard flow
|
||||
#[serde(rename = "artcraft_get_web")]
|
||||
ArtCraftGetWeb,
|
||||
|
||||
/// getartcraft.com stripe checkout flow
|
||||
#[serde(rename = "artcraft_get_s")]
|
||||
ArtCraftGetStripe,
|
||||
|
||||
#[serde(rename = "fakeyou")]
|
||||
FakeYou,
|
||||
|
||||
#[serde(rename = "storyteller")]
|
||||
Storyteller,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserSignupSource);
|
||||
impl_mysql_enum_coders!(UserSignupSource);
|
||||
impl_mysql_from_row!(UserSignupSource);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserSignupSource {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ArtCraft => "artcraft",
|
||||
Self::ArtCraftApp => "artcraft_app",
|
||||
Self::ArtCraftAiWeb => "artcraft_ai_web",
|
||||
Self::ArtCraftAiStripe => "artcraft_ai_s",
|
||||
Self::ArtCraftGetWeb => "artcraft_get_web",
|
||||
Self::ArtCraftGetStripe => "artcraft_get_s",
|
||||
Self::FakeYou => "fakeyou",
|
||||
Self::Storyteller => "storyteller",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"artcraft" => Ok(Self::ArtCraft),
|
||||
"artcraft_app" => Ok(Self::ArtCraftApp),
|
||||
"artcraft_ai_web" => Ok(Self::ArtCraftAiWeb),
|
||||
"artcraft_ai_s" => Ok(Self::ArtCraftAiStripe),
|
||||
"artcraft_get_web" => Ok(Self::ArtCraftGetWeb),
|
||||
"artcraft_get_s" => Ok(Self::ArtCraftGetStripe),
|
||||
"fakeyou" => Ok(Self::FakeYou),
|
||||
"storyteller" => Ok(Self::Storyteller),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::ArtCraft,
|
||||
Self::ArtCraftApp,
|
||||
Self::ArtCraftAiWeb,
|
||||
Self::ArtCraftAiStripe,
|
||||
Self::ArtCraftGetWeb,
|
||||
Self::ArtCraftGetStripe,
|
||||
Self::FakeYou,
|
||||
Self::Storyteller,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::users::user_signup_source::UserSignupSource;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserSignupSource::ArtCraft, "artcraft");
|
||||
assert_serialization(UserSignupSource::ArtCraftApp, "artcraft_app");
|
||||
assert_serialization(UserSignupSource::ArtCraftAiWeb, "artcraft_ai_web");
|
||||
assert_serialization(UserSignupSource::ArtCraftAiStripe, "artcraft_ai_s");
|
||||
assert_serialization(UserSignupSource::ArtCraftGetWeb, "artcraft_get_web");
|
||||
assert_serialization(UserSignupSource::ArtCraftGetStripe, "artcraft_get_s");
|
||||
assert_serialization(UserSignupSource::FakeYou, "fakeyou");
|
||||
assert_serialization(UserSignupSource::Storyteller, "storyteller");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(UserSignupSource::ArtCraft.to_str(), "artcraft");
|
||||
assert_eq!(UserSignupSource::ArtCraftApp.to_str(), "artcraft_app");
|
||||
assert_eq!(UserSignupSource::ArtCraftAiWeb.to_str(), "artcraft_ai_web");
|
||||
assert_eq!(UserSignupSource::ArtCraftAiStripe.to_str(), "artcraft_ai_s");
|
||||
assert_eq!(UserSignupSource::ArtCraftGetWeb.to_str(), "artcraft_get_web");
|
||||
assert_eq!(UserSignupSource::FakeYou.to_str(), "fakeyou");
|
||||
assert_eq!(UserSignupSource::Storyteller.to_str(), "storyteller");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(UserSignupSource::from_str("artcraft").unwrap(), UserSignupSource::ArtCraft);
|
||||
assert_eq!(UserSignupSource::from_str("artcraft_app").unwrap(), UserSignupSource::ArtCraftApp);
|
||||
assert_eq!(UserSignupSource::from_str("artcraft_ai_web").unwrap(), UserSignupSource::ArtCraftAiWeb);
|
||||
assert_eq!(UserSignupSource::from_str("artcraft_ai_s").unwrap(), UserSignupSource::ArtCraftAiStripe);
|
||||
assert_eq!(UserSignupSource::from_str("artcraft_get_web").unwrap(), UserSignupSource::ArtCraftGetWeb);
|
||||
assert_eq!(UserSignupSource::from_str("artcraft_get_s").unwrap(), UserSignupSource::ArtCraftGetStripe);
|
||||
assert_eq!(UserSignupSource::from_str("fakeyou").unwrap(), UserSignupSource::FakeYou);
|
||||
assert_eq!(UserSignupSource::from_str("storyteller").unwrap(), UserSignupSource::Storyteller);
|
||||
assert!(UserSignupSource::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = UserSignupSource::all_variants();
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraft));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraftApp));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraftAiWeb));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraftAiStripe));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraftGetWeb));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::ArtCraftGetStripe));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::FakeYou));
|
||||
assert_eq!(variants.pop_first(), Some(UserSignupSource::Storyteller));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(UserSignupSource::all_variants().len(), UserSignupSource::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in UserSignupSource::all_variants() {
|
||||
assert_eq!(variant, UserSignupSource::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, UserSignupSource::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, UserSignupSource::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in UserSignupSource::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod voice_conversion_model_type;
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `voice_conversion_models` table in `VARCHAR(32)` field `model_type`.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum VoiceConversionModelType {
|
||||
// We're skipping RVC "v1" models as "v2" are much higher quality.
|
||||
// Future incompatible upgrades may deserve a different enum variant.
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
|
||||
#[serde(rename = "soft_vc")]
|
||||
SoftVc,
|
||||
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(VoiceConversionModelType);
|
||||
impl_mysql_enum_coders!(VoiceConversionModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl VoiceConversionModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::SoftVc => "soft_vc",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"soft_vc" => Ok(Self::SoftVc),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::RvcV2,
|
||||
Self::SoftVc,
|
||||
Self::SoVitsSvc,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(VoiceConversionModelType::RvcV2, "rvc_v2");
|
||||
assert_serialization(VoiceConversionModelType::SoftVc, "soft_vc");
|
||||
assert_serialization(VoiceConversionModelType::SoVitsSvc, "so_vits_svc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(VoiceConversionModelType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(VoiceConversionModelType::SoftVc.to_str(), "soft_vc");
|
||||
assert_eq!(VoiceConversionModelType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(VoiceConversionModelType::from_str("rvc_v2").unwrap(), VoiceConversionModelType::RvcV2);
|
||||
assert_eq!(VoiceConversionModelType::from_str("soft_vc").unwrap(), VoiceConversionModelType::SoftVc);
|
||||
assert_eq!(VoiceConversionModelType::from_str("so_vits_svc").unwrap(), VoiceConversionModelType::SoVitsSvc);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = VoiceConversionModelType::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert_eq!(variants.pop_first(), Some(VoiceConversionModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(VoiceConversionModelType::SoftVc));
|
||||
assert_eq!(variants.pop_first(), Some(VoiceConversionModelType::SoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(VoiceConversionModelType::all_variants().len(), VoiceConversionModelType::iter().len());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod voice_conversion_media_token_type;
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `voice_conversion_results` table in a `VARCHAR` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum VoiceConversionMediaTokenType {
|
||||
/// Media token refers to record in `media_uploads` table.
|
||||
MediaUpload,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(VoiceConversionMediaTokenType);
|
||||
impl_mysql_enum_coders!(VoiceConversionMediaTokenType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl VoiceConversionMediaTokenType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::MediaUpload => "media_upload",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"media_upload" => Ok(Self::MediaUpload),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::voice_conversion_results::voice_conversion_media_token_type::VoiceConversionMediaTokenType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(VoiceConversionMediaTokenType::MediaUpload, "media_upload");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(VoiceConversionMediaTokenType::MediaUpload.to_str(), "media_upload");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(VoiceConversionMediaTokenType::from_str("media_upload").unwrap(), VoiceConversionMediaTokenType::MediaUpload);
|
||||
assert!(VoiceConversionMediaTokenType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod wallet_ledger_entry_type;
|
||||
-204
@@ -1,204 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `wallet_ledger_entries` table in a `VARCHAR(16)` field.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WalletLedgerEntryType {
|
||||
/// Wallet created
|
||||
#[serde(rename = "create")]
|
||||
Create,
|
||||
|
||||
/// Credit durable banked balance
|
||||
#[serde(rename = "credit_banked")]
|
||||
CreditBanked,
|
||||
|
||||
/// Credit monthly refill
|
||||
#[serde(rename = "credit_monthly")]
|
||||
CreditMonthly,
|
||||
|
||||
/// Deduct credits (mixed durable and monthly deduction)
|
||||
#[serde(rename = "deduct_mixed")]
|
||||
DeductMixed,
|
||||
|
||||
/// Deduct durable banked credits
|
||||
#[serde(rename = "deduct_banked")]
|
||||
DeductBanked,
|
||||
|
||||
/// Deduct monthly credits
|
||||
#[serde(rename = "deduct_monthly")]
|
||||
DeductMonthly,
|
||||
|
||||
/// Refund banked credits
|
||||
#[serde(rename = "refund_banked")]
|
||||
RefundBanked,
|
||||
|
||||
/// Support staff manually credit account
|
||||
#[serde(rename = "staff_add_banked")]
|
||||
StaffAddBanked,
|
||||
|
||||
// TODO: No clean way to do "mixed" refunds yet, and if we
|
||||
// refund close to the cutoff it might be unfair. Let's
|
||||
// just not do monthly refunds yet and instead credit our
|
||||
// users with banked credits.
|
||||
// /// Refund monthly credits
|
||||
// #[serde(rename = "refund_monthly")]
|
||||
// RefundMonthly,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(WalletLedgerEntryType);
|
||||
impl_mysql_enum_coders!(WalletLedgerEntryType);
|
||||
impl_mysql_from_row!(WalletLedgerEntryType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl WalletLedgerEntryType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Create => "create",
|
||||
Self::CreditBanked => "credit_banked",
|
||||
Self::CreditMonthly => "credit_monthly",
|
||||
Self::DeductMixed => "deduct_mixed",
|
||||
Self::DeductBanked => "deduct_banked",
|
||||
Self::DeductMonthly => "deduct_monthly",
|
||||
Self::RefundBanked => "refund_banked",
|
||||
Self::StaffAddBanked => "staff_add_banked",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"create" => Ok(Self::Create),
|
||||
"credit_banked" => Ok(Self::CreditBanked),
|
||||
"credit_monthly" => Ok(Self::CreditMonthly),
|
||||
"deduct_mixed" => Ok(Self::DeductMixed),
|
||||
"deduct_banked" => Ok(Self::DeductBanked),
|
||||
"deduct_monthly" => Ok(Self::DeductMonthly),
|
||||
"refund_banked" => Ok(Self::RefundBanked),
|
||||
"staff_add_banked" => Ok(Self::StaffAddBanked),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Create,
|
||||
Self::CreditBanked,
|
||||
Self::CreditMonthly,
|
||||
Self::DeductMixed,
|
||||
Self::DeductBanked,
|
||||
Self::DeductMonthly,
|
||||
Self::RefundBanked,
|
||||
Self::StaffAddBanked,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(WalletLedgerEntryType::Create, "create");
|
||||
assert_serialization(WalletLedgerEntryType::CreditBanked, "credit_banked");
|
||||
assert_serialization(WalletLedgerEntryType::CreditMonthly, "credit_monthly");
|
||||
assert_serialization(WalletLedgerEntryType::DeductMixed, "deduct_mixed");
|
||||
assert_serialization(WalletLedgerEntryType::DeductBanked, "deduct_banked");
|
||||
assert_serialization(WalletLedgerEntryType::DeductMonthly, "deduct_monthly");
|
||||
assert_serialization(WalletLedgerEntryType::RefundBanked, "refund_banked");
|
||||
assert_serialization(WalletLedgerEntryType::StaffAddBanked, "staff_add_banked");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(WalletLedgerEntryType::Create.to_str(), "create");
|
||||
assert_eq!(WalletLedgerEntryType::CreditBanked.to_str(), "credit_banked");
|
||||
assert_eq!(WalletLedgerEntryType::CreditMonthly.to_str(), "credit_monthly");
|
||||
assert_eq!(WalletLedgerEntryType::DeductMixed.to_str(), "deduct_mixed");
|
||||
assert_eq!(WalletLedgerEntryType::DeductBanked.to_str(), "deduct_banked");
|
||||
assert_eq!(WalletLedgerEntryType::DeductMonthly.to_str(), "deduct_monthly");
|
||||
assert_eq!(WalletLedgerEntryType::RefundBanked.to_str(), "refund_banked");
|
||||
assert_eq!(WalletLedgerEntryType::StaffAddBanked.to_str(), "staff_add_banked");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(WalletLedgerEntryType::from_str("create").unwrap(), WalletLedgerEntryType::Create);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("credit_banked").unwrap(), WalletLedgerEntryType::CreditBanked);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("credit_monthly").unwrap(), WalletLedgerEntryType::CreditMonthly);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("deduct_mixed").unwrap(), WalletLedgerEntryType::DeductMixed);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("deduct_banked").unwrap(), WalletLedgerEntryType::DeductBanked);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("deduct_monthly").unwrap(), WalletLedgerEntryType::DeductMonthly);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("refund_banked").unwrap(), WalletLedgerEntryType::RefundBanked);
|
||||
assert_eq!(WalletLedgerEntryType::from_str("staff_add_banked").unwrap(), WalletLedgerEntryType::StaffAddBanked);
|
||||
assert!(WalletLedgerEntryType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = WalletLedgerEntryType::all_variants();
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::Create));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::CreditBanked));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::CreditMonthly));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductMixed));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductBanked));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductMonthly));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::RefundBanked));
|
||||
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::StaffAddBanked));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(WalletLedgerEntryType::all_variants().len(), WalletLedgerEntryType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in WalletLedgerEntryType::all_variants() {
|
||||
assert_eq!(variant, WalletLedgerEntryType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, WalletLedgerEntryType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, WalletLedgerEntryType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in WalletLedgerEntryType::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod rendition_status;
|
||||
@@ -1,96 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the SqLite `web_scraping_targets` table in a `TEXT` field named `scraping_status`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum RenditionStatus {
|
||||
#[serde(rename = "new")]
|
||||
New,
|
||||
|
||||
#[serde(rename = "skipped")]
|
||||
Skipped,
|
||||
|
||||
#[serde(rename = "failed")]
|
||||
Failed,
|
||||
|
||||
#[serde(rename = "permanently_failed")]
|
||||
PermanentlyFailed,
|
||||
|
||||
#[serde(rename = "success")]
|
||||
Success,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(RenditionStatus);
|
||||
impl_sqlite_enum_coders!(RenditionStatus);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl RenditionStatus {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::New => "new",
|
||||
Self::Skipped => "skipped",
|
||||
Self::Failed => "failed",
|
||||
Self::PermanentlyFailed => "permanently_failed",
|
||||
Self::Success => "success",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"new" => Ok(Self::New),
|
||||
"skipped" => Ok(Self::Skipped),
|
||||
"failed" => Ok(Self::Failed),
|
||||
"permanently_failed" => Ok(Self::PermanentlyFailed),
|
||||
"success" => Ok(Self::Success),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::web_rendition_targets::rendition_status::RenditionStatus;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(RenditionStatus::New, "new");
|
||||
assert_serialization(RenditionStatus::Skipped, "skipped");
|
||||
assert_serialization(RenditionStatus::Failed, "failed");
|
||||
assert_serialization(RenditionStatus::PermanentlyFailed, "permanently_failed");
|
||||
assert_serialization(RenditionStatus::Success, "success");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(RenditionStatus::New.to_str(), "new");
|
||||
assert_eq!(RenditionStatus::Skipped.to_str(), "skipped");
|
||||
assert_eq!(RenditionStatus::Failed.to_str(), "failed");
|
||||
assert_eq!(RenditionStatus::PermanentlyFailed.to_str(), "permanently_failed");
|
||||
assert_eq!(RenditionStatus::Success.to_str(), "success");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(RenditionStatus::from_str("new").unwrap(), RenditionStatus::New);
|
||||
assert_eq!(RenditionStatus::from_str("skipped").unwrap(), RenditionStatus::Skipped);
|
||||
assert_eq!(RenditionStatus::from_str("failed").unwrap(), RenditionStatus::Failed);
|
||||
assert_eq!(RenditionStatus::from_str("permanently_failed").unwrap(), RenditionStatus::PermanentlyFailed);
|
||||
assert_eq!(RenditionStatus::from_str("success").unwrap(), RenditionStatus::Success);
|
||||
assert!(RenditionStatus::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod scraping_status;
|
||||
@@ -1,96 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the SqLite `web_scraping_targets` table in a `TEXT` field named `scraping_status`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum ScrapingStatus {
|
||||
#[serde(rename = "new")]
|
||||
New,
|
||||
|
||||
#[serde(rename = "skipped")]
|
||||
Skipped,
|
||||
|
||||
#[serde(rename = "failed")]
|
||||
Failed,
|
||||
|
||||
#[serde(rename = "permanently_failed")]
|
||||
PermanentlyFailed,
|
||||
|
||||
#[serde(rename = "success")]
|
||||
Success,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ScrapingStatus);
|
||||
impl_sqlite_enum_coders!(ScrapingStatus);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ScrapingStatus {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::New => "new",
|
||||
Self::Skipped => "skipped",
|
||||
Self::Failed => "failed",
|
||||
Self::PermanentlyFailed => "permanently_failed",
|
||||
Self::Success => "success",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"new" => Ok(Self::New),
|
||||
"skipped" => Ok(Self::Skipped),
|
||||
"failed" => Ok(Self::Failed),
|
||||
"permanently_failed" => Ok(Self::PermanentlyFailed),
|
||||
"success" => Ok(Self::Success),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::web_scraping_targets::scraping_status::ScrapingStatus;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ScrapingStatus::New, "new");
|
||||
assert_serialization(ScrapingStatus::Skipped, "skipped");
|
||||
assert_serialization(ScrapingStatus::Failed, "failed");
|
||||
assert_serialization(ScrapingStatus::PermanentlyFailed, "permanently_failed");
|
||||
assert_serialization(ScrapingStatus::Success, "success");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(ScrapingStatus::New.to_str(), "new");
|
||||
assert_eq!(ScrapingStatus::Skipped.to_str(), "skipped");
|
||||
assert_eq!(ScrapingStatus::Failed.to_str(), "failed");
|
||||
assert_eq!(ScrapingStatus::PermanentlyFailed.to_str(), "permanently_failed");
|
||||
assert_eq!(ScrapingStatus::Success.to_str(), "success");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(ScrapingStatus::from_str("new").unwrap(), ScrapingStatus::New);
|
||||
assert_eq!(ScrapingStatus::from_str("skipped").unwrap(), ScrapingStatus::Skipped);
|
||||
assert_eq!(ScrapingStatus::from_str("failed").unwrap(), ScrapingStatus::Failed);
|
||||
assert_eq!(ScrapingStatus::from_str("permanently_failed").unwrap(), ScrapingStatus::PermanentlyFailed);
|
||||
assert_eq!(ScrapingStatus::from_str("success").unwrap(), ScrapingStatus::Success);
|
||||
assert!(ScrapingStatus::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `zs_voices` table in a `VARCHAR(16)` field named `encoding_type`.
|
||||
///
|
||||
/// This indicates what type of features are used in the embeddings.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum ZsVoiceEncodingType {
|
||||
/// Encodec features
|
||||
#[serde(rename = "encodec")]
|
||||
Encodec,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ZsVoiceEncodingType);
|
||||
impl_mysql_enum_coders!(ZsVoiceEncodingType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ZsVoiceEncodingType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Encodec => "encodec",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"encodec" => Ok(Self::Encodec),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Encodec,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::zs_voices::encoding_type::ZsVoiceEncodingType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ZsVoiceEncodingType::Encodec, "encodec");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(ZsVoiceEncodingType::Encodec.to_str(), "encodec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(ZsVoiceEncodingType::from_str("encodec").unwrap(), ZsVoiceEncodingType::Encodec);
|
||||
assert!(ZsVoiceEncodingType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = ZsVoiceEncodingType::all_variants();
|
||||
assert_eq!(variants.len(), 1);
|
||||
assert_eq!(variants.pop_first(), Some(ZsVoiceEncodingType::Encodec));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(ZsVoiceEncodingType::all_variants().len(), ZsVoiceEncodingType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in ZsVoiceEncodingType::all_variants() {
|
||||
assert_eq!(variant, ZsVoiceEncodingType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, ZsVoiceEncodingType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, ZsVoiceEncodingType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod encoding_type;
|
||||
pub mod model_category;
|
||||
pub mod model_type;
|
||||
@@ -1,108 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `zs_voices` table in a `VARCHAR(16)` field named `model_category`.
|
||||
///
|
||||
/// This indicates what type of features are used in the embeddings.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum ZsVoiceModelCategory {
|
||||
/// TTS-type zero shot models
|
||||
#[serde(rename = "tts")]
|
||||
Tts,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ZsVoiceModelCategory);
|
||||
impl_mysql_enum_coders!(ZsVoiceModelCategory);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ZsVoiceModelCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Tts => "tts",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"tts" => Ok(Self::Tts),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::Tts,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::zs_voices::model_category::ZsVoiceModelCategory;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ZsVoiceModelCategory::Tts, "tts");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(ZsVoiceModelCategory::Tts.to_str(), "tts");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(ZsVoiceModelCategory::from_str("tts").unwrap(), ZsVoiceModelCategory::Tts);
|
||||
assert!(ZsVoiceModelCategory::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = ZsVoiceModelCategory::all_variants();
|
||||
assert_eq!(variants.len(), 1);
|
||||
assert_eq!(variants.pop_first(), Some(ZsVoiceModelCategory::Tts));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(ZsVoiceModelCategory::all_variants().len(), ZsVoiceModelCategory::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in ZsVoiceModelCategory::all_variants() {
|
||||
assert_eq!(variant, ZsVoiceModelCategory::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, ZsVoiceModelCategory::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, ZsVoiceModelCategory::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `zs_voices` table in a `VARCHAR(16)` field named `model_type`.
|
||||
///
|
||||
/// This indicates what type of features are used in the embeddings.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum ZsVoiceModelType {
|
||||
/// TTS-type zero shot models
|
||||
#[serde(rename = "vall-e-x")]
|
||||
VallEX,
|
||||
#[serde(rename = "styletts2")]
|
||||
StyleTTS2,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(ZsVoiceModelType);
|
||||
impl_mysql_enum_coders!(ZsVoiceModelType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl ZsVoiceModelType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::VallEX=> "vall-e-x",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"vall-e-x" => Ok(Self::VallEX),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::VallEX,
|
||||
Self::StyleTTS2,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::zs_voices::model_type::ZsVoiceModelType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(ZsVoiceModelType::VallEX, "vall-e-x");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(ZsVoiceModelType::VallEX.to_str(), "vall-e-x");
|
||||
assert_eq!(ZsVoiceModelType::StyleTTS2.to_str(), "styletts2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(ZsVoiceModelType::from_str("vall-e-x").unwrap(), ZsVoiceModelType::VallEX);
|
||||
assert_eq!(ZsVoiceModelType::from_str("styletts2").unwrap(), ZsVoiceModelType::StyleTTS2);
|
||||
assert!(ZsVoiceModelType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = ZsVoiceModelType::all_variants();
|
||||
assert_eq!(variants.len(), 2);
|
||||
assert_eq!(variants.pop_first(), Some(ZsVoiceModelType::VallEX));
|
||||
assert_eq!(variants.pop_first(), Some(ZsVoiceModelType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(ZsVoiceModelType::all_variants().len(), ZsVoiceModelType::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in ZsVoiceModelType::all_variants() {
|
||||
assert_eq!(variant, ZsVoiceModelType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, ZsVoiceModelType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, ZsVoiceModelType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ mod macros;
|
||||
|
||||
#[cfg(test)] pub mod test_helpers;
|
||||
|
||||
pub mod by_table;
|
||||
// by_table has been migrated to enums_db and enums_api crates
|
||||
pub mod common;
|
||||
pub mod error;
|
||||
pub mod no_table;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use crate::api_safe::by_table::generic_inference_jobs::frontend_failure_category_for_api_clients::FrontendFailureCategoryForApiClients;
|
||||
use crate::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums_db::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use crate::error::enum_error::EnumError;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
|
||||
+2
-10
@@ -23,8 +23,6 @@ use bucket_paths::legacy::typified_paths::public::voice_conversion_results::buck
|
||||
use chrono::{DateTime, Utc};
|
||||
use enums::api_safe::by_table::generic_inference_jobs::frontend_failure_category_for_api_clients::FrontendFailureCategoryForApiClients;
|
||||
use enums::api_safe::by_table::generic_inference_jobs::frontend_failure_category_for_old_clients::FrontendFailureCategoryForOldClients;
|
||||
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory as EnumsFrontendFailureCategory;
|
||||
use enums_api::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
|
||||
use enums_api::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums_convert::by_table::generic_inference_jobs::inference_category::inference_category_to_api;
|
||||
use enums::common::job_status_plus::JobStatusPlus;
|
||||
@@ -296,16 +294,10 @@ fn db_record_to_response_payload(
|
||||
requires_keepalive: record.is_keepalive_required,
|
||||
maybe_failure_category: record
|
||||
.maybe_frontend_failure_category
|
||||
.and_then(|val| {
|
||||
let old = EnumsFrontendFailureCategory::from_str(val.to_str()).ok()?;
|
||||
FrontendFailureCategoryForOldClients::try_from_db_enum(old)
|
||||
}),
|
||||
.and_then(|val| FrontendFailureCategoryForOldClients::try_from_db_enum(val)),
|
||||
maybe_failure_category_updated: record
|
||||
.maybe_frontend_failure_category
|
||||
.and_then(|val| {
|
||||
let old = EnumsFrontendFailureCategory::from_str(val.to_str()).ok()?;
|
||||
Some(FrontendFailureCategoryForApiClients::from_db_enum(old))
|
||||
}),
|
||||
.map(|val| FrontendFailureCategoryForApiClients::from_db_enum(val)),
|
||||
maybe_failure_message: record.failure_reason,
|
||||
progress_percentage,
|
||||
maybe_current_execution_duration_seconds,
|
||||
|
||||
Reference in new issue
Block a user