diff --git a/tests/common/features/json_vec.rs b/tests/common/features/json_vec.rs new file mode 100644 index 00000000..7b347c7b --- /dev/null +++ b/tests/common/features/json_vec.rs @@ -0,0 +1,51 @@ +use sea_orm::entity::prelude::*; +use sea_orm::{TryGetError, TryGetable}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "json_vec")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub str_vec: StringVec, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct StringVec(pub Vec); + +impl From for Value { + fn from(source: StringVec) -> Self { + Value::String(serde_json::to_string(&source).ok().map(|s| Box::new(s))) + } +} + +impl TryGetable for StringVec { + fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { + let json_str: String = res.try_get(pre, col).map_err(TryGetError::DbErr)?; + serde_json::from_str(&json_str).map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string()))) + } +} + +impl sea_query::ValueType for StringVec { + fn try_from(v: Value) -> Result { + match v { + Value::String(Some(x)) => Ok(StringVec( + serde_json::from_str(&x).map_err(|_| sea_query::ValueTypeErr)?, + )), + _ => Err(sea_query::ValueTypeErr), + } + } + + fn type_name() -> String { + stringify!(StringVec).to_owned() + } + + fn column_type() -> sea_query::ColumnType { + sea_query::ColumnType::String(None) + } +} diff --git a/tests/common/features/mod.rs b/tests/common/features/mod.rs index 4dad7956..fc9ac047 100644 --- a/tests/common/features/mod.rs +++ b/tests/common/features/mod.rs @@ -3,6 +3,7 @@ pub mod active_enum_child; pub mod applog; pub mod byte_primary_key; pub mod insert_default; +pub mod json_vec; pub mod metadata; pub mod repository; pub mod satellite; @@ -16,6 +17,7 @@ pub use active_enum_child::Entity as ActiveEnumChild; pub use applog::Entity as Applog; pub use byte_primary_key::Entity as BytePrimaryKey; pub use insert_default::Entity as InsertDefault; +pub use json_vec::Entity as JsonVec; pub use metadata::Entity as Metadata; pub use repository::Entity as Repository; pub use satellite::Entity as Satellite; diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index 68f2f281..10fd038c 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -18,6 +18,7 @@ pub async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> { create_byte_primary_key_table(db).await?; create_satellites_table(db).await?; create_transaction_log_table(db).await?; + create_json_vec_table(db).await?; let create_enum_stmts = match db_backend { DbBackend::MySql | DbBackend::Sqlite => Vec::new(), @@ -286,3 +287,23 @@ pub async fn create_insert_default_table(db: &DbConn) -> Result Result { + let create_table_stmt = sea_query::Table::create() + .table(json_vec::Entity.table_ref()) + .col( + ColumnDef::new(json_vec::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(json_vec::Column::StrVec) + .string() + .not_null(), + ) + .to_owned(); + + create_table(db, &create_table_stmt, JsonVec).await +} diff --git a/tests/json_vec_tests.rs b/tests/json_vec_tests.rs new file mode 100644 index 00000000..de8c819b --- /dev/null +++ b/tests/json_vec_tests.rs @@ -0,0 +1,47 @@ +pub mod common; + +pub use common::{features::*, setup::*, TestContext}; +use pretty_assertions::assert_eq; +use sea_orm::{entity::prelude::*, entity::*, DatabaseConnection}; + +#[sea_orm_macros::test] +#[cfg(any( + feature = "sqlx-mysql", + feature = "sqlx-sqlite", + feature = "sqlx-postgres" +))] +async fn main() -> Result<(), DbErr> { + let ctx = TestContext::new("json_vec_tests").await; + create_tables(&ctx.db).await?; + insert_json_vec(&ctx.db).await?; + ctx.delete().await; + + Ok(()) +} + +pub async fn insert_json_vec(db: &DatabaseConnection) -> Result<(), DbErr> { + let json_vec = json_vec::Model { + id: 1, + str_vec: json_vec::StringVec(vec![ + "1".to_string(), + "2".to_string(), + "3".to_string(), + ]) + }; + + let result = json_vec.clone().into_active_model().insert(db).await?; + + assert_eq!(result, json_vec); + + let model = json_vec::Entity::find() + .filter(json_vec::Column::Id.eq(json_vec.id)) + .one(db) + .await?; + + assert_eq!( + model, + Some(json_vec) + ); + + Ok(()) +}