From 1455068e0c0eface8bb1228690603f9460614d4e Mon Sep 17 00:00:00 2001 From: Namekuji Date: Wed, 31 May 2023 12:09:30 -0400 Subject: [PATCH] add newtype --- .../native-utils/crates/model/Cargo.toml | 1 + .../crates/model/src/entity/antenna.rs | 10 ++-- .../crates/model/src/entity/mod.rs | 1 + .../crates/model/src/entity/newtype/macros.rs | 51 +++++++++++++++++++ .../crates/model/src/entity/newtype/mod.rs | 17 +++++++ .../crates/model/src/repository/antenna.rs | 8 +-- .../crates/model/src/schema/antenna.rs | 12 ++--- .../crates/model/src/schema/mod.rs | 30 ----------- .../native-utils/crates/model/tests/common.rs | 13 +++-- .../crates/model/tests/repository/antenna.rs | 10 ++-- 10 files changed, 101 insertions(+), 52 deletions(-) create mode 100644 packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs create mode 100644 packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs diff --git a/packages/backend/native-utils/crates/model/Cargo.toml b/packages/backend/native-utils/crates/model/Cargo.toml index 87f712aa7e..47d2e15537 100644 --- a/packages/backend/native-utils/crates/model/Cargo.toml +++ b/packages/backend/native-utils/crates/model/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" async-trait = "0.1.68" chrono = "0.4.24" database = { path = "../database" } +derive_more = "0.99.17" jsonschema = "0.17.0" once_cell = "1.17.1" parse-display = "0.8.0" diff --git a/packages/backend/native-utils/crates/model/src/entity/antenna.rs b/packages/backend/native-utils/crates/model/src/entity/antenna.rs index 513d15e831..5e514576be 100644 --- a/packages/backend/native-utils/crates/model/src/entity/antenna.rs +++ b/packages/backend/native-utils/crates/model/src/entity/antenna.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 -use super::sea_orm_active_enums::AntennaSrcEnum; +use super::{newtype, sea_orm_active_enums::AntennaSrcEnum}; use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] @@ -17,7 +17,7 @@ pub struct Model { #[sea_orm(column_name = "userListId")] pub user_list_id: Option, #[sea_orm(column_type = "JsonBinary")] - pub keywords: Json, + pub keywords: newtype::Keyword, #[sea_orm(column_name = "withFile")] pub with_file: bool, pub expression: Option, @@ -28,11 +28,11 @@ pub struct Model { pub with_replies: bool, #[sea_orm(column_name = "userGroupJoiningId")] pub user_group_joining_id: Option, - pub users: Vec, + pub users: newtype::StringVec, #[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")] - pub exclude_keywords: Json, + pub exclude_keywords: newtype::Keyword, #[sea_orm(column_type = "JsonBinary")] - pub instances: Json, + pub instances: newtype::StringVec, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/packages/backend/native-utils/crates/model/src/entity/mod.rs b/packages/backend/native-utils/crates/model/src/entity/mod.rs index 077f9fa6e7..6105b05550 100644 --- a/packages/backend/native-utils/crates/model/src/entity/mod.rs +++ b/packages/backend/native-utils/crates/model/src/entity/mod.rs @@ -33,6 +33,7 @@ pub mod migrations; pub mod moderation_log; pub mod muted_note; pub mod muting; +pub mod newtype; pub mod note; pub mod note_edit; pub mod note_favorite; diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs new file mode 100644 index 0000000000..0266e80c85 --- /dev/null +++ b/packages/backend/native-utils/crates/model/src/entity/newtype/macros.rs @@ -0,0 +1,51 @@ +#[macro_export] +macro_rules! impl_json_newtype { + ($a:tt) => { + impl From<$a> for Value { + fn from(source: $a) -> Self { + Value::Json(serde_json::to_value(source).ok().map(Box::new)) + } + } + + impl TryGetable for $a { + fn try_get_by( + res: &QueryResult, + idx: I, + ) -> Result { + let json_value: serde_json::Value = + res.try_get_by(idx).map_err(TryGetError::DbErr)?; + serde_json::from_value(json_value) + .map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string()))) + } + } + + impl sea_query::ValueType for $a { + fn try_from(v: Value) -> Result { + match v { + Value::Json(Some(x)) => Ok($a( + serde_json::from_value(*x).map_err(|_| sea_query::ValueTypeErr)? + )), + _ => Err(sea_query::ValueTypeErr), + } + } + + fn type_name() -> String { + stringify!($a).to_owned() + } + + fn array_type() -> sea_orm::sea_query::ArrayType { + sea_orm::sea_query::ArrayType::Json + } + + fn column_type() -> sea_query::ColumnType { + sea_query::ColumnType::Json + } + } + + impl sea_query::Nullable for $a { + fn null() -> Value { + Value::Json(None) + } + } + }; +} diff --git a/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs new file mode 100644 index 0000000000..714f3dafb7 --- /dev/null +++ b/packages/backend/native-utils/crates/model/src/entity/newtype/mod.rs @@ -0,0 +1,17 @@ +mod macros; + +use derive_more::From; +use schemars::JsonSchema; +use sea_orm::{sea_query, DbErr, QueryResult, TryGetError, TryGetable, Value}; +use serde::{Deserialize, Serialize}; + +use crate::impl_json_newtype; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)] +pub struct Keyword(pub Vec>); +impl_json_newtype!(Keyword); + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, From)] + +pub struct StringVec(pub Vec); +impl_json_newtype!(StringVec); diff --git a/packages/backend/native-utils/crates/model/src/repository/antenna.rs b/packages/backend/native-utils/crates/model/src/repository/antenna.rs index dc6cb5a016..9a6882b59a 100644 --- a/packages/backend/native-utils/crates/model/src/repository/antenna.rs +++ b/packages/backend/native-utils/crates/model/src/repository/antenna.rs @@ -3,7 +3,7 @@ use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use crate::entity::{antenna, antenna_note, user_group_joining}; use crate::error::Error; -use crate::schema::{antenna::Antenna, json_to_keyword, json_to_string_list}; +use crate::schema::antenna::Antenna; use super::Repository; @@ -30,13 +30,13 @@ impl Repository for antenna::Model { id: self.id, created_at: self.created_at.into(), name: self.name, - keywords: json_to_keyword(&self.keywords), - exclude_keywords: json_to_keyword(&self.exclude_keywords), + keywords: self.keywords, + exclude_keywords: self.exclude_keywords, src: self.src.try_into()?, user_list_id: self.user_list_id, user_group_id, users: self.users, - instances: json_to_string_list(&self.instances), + instances: self.instances, case_sensitive: self.case_sensitive, notify: self.notify, with_replies: self.with_replies, diff --git a/packages/backend/native-utils/crates/model/src/schema/antenna.rs b/packages/backend/native-utils/crates/model/src/schema/antenna.rs index d5f19a96f7..035dca344c 100644 --- a/packages/backend/native-utils/crates/model/src/schema/antenna.rs +++ b/packages/backend/native-utils/crates/model/src/schema/antenna.rs @@ -4,8 +4,8 @@ use parse_display::FromStr; use schemars::JsonSchema; use utoipa::ToSchema; -use super::{Keyword, Schema, StringList}; -use crate::entity::sea_orm_active_enums::AntennaSrcEnum; +use super::Schema; +use crate::entity::{newtype, sea_orm_active_enums::AntennaSrcEnum}; #[derive(Clone, Debug, PartialEq, Eq, JsonSchema, ToSchema)] #[serde(rename_all = "camelCase")] @@ -13,14 +13,14 @@ pub struct Antenna { pub id: String, pub created_at: chrono::DateTime, pub name: String, - pub keywords: Keyword, - pub exclude_keywords: Keyword, + pub keywords: newtype::Keyword, + pub exclude_keywords: newtype::Keyword, #[schema(inline)] pub src: AntennaSrc, pub user_list_id: Option, pub user_group_id: Option, - pub users: StringList, - pub instances: StringList, + pub users: newtype::StringVec, + pub instances: newtype::StringVec, #[serde(default)] pub case_sensitive: bool, #[serde(default)] diff --git a/packages/backend/native-utils/crates/model/src/schema/mod.rs b/packages/backend/native-utils/crates/model/src/schema/mod.rs index 2a0853814b..cc495aac1b 100644 --- a/packages/backend/native-utils/crates/model/src/schema/mod.rs +++ b/packages/backend/native-utils/crates/model/src/schema/mod.rs @@ -3,10 +3,6 @@ pub mod app; use jsonschema::JSONSchema; use schemars::{schema_for, JsonSchema}; -use serde_json::Value; - -type Keyword = Vec>; -type StringList = Vec; /// Structs of schema defitions implement this trait in order to /// provide the JSON Schema validator [`jsonschema::JSONSchema`]. @@ -23,29 +19,3 @@ trait Schema { .expect("Unable to compile schema") } } - -pub(crate) fn json_to_keyword(value: &Value) -> Keyword { - match value.as_array() { - None => vec![vec![]], - Some(or_vec) => or_vec - .iter() - .map(|and_val| match and_val.as_array() { - None => vec![], - Some(and_vec) => and_vec - .iter() - .map(|word| word.as_str().unwrap_or_default().to_string()) - .collect(), - }) - .collect(), - } -} - -pub(crate) fn json_to_string_list(value: &Value) -> StringList { - match value.as_array() { - None => vec![], - Some(v) => v - .iter() - .map(|s| s.as_str().unwrap_or_default().to_string()) - .collect(), - } -} diff --git a/packages/backend/native-utils/crates/model/tests/common.rs b/packages/backend/native-utils/crates/model/tests/common.rs index 38c6160711..6a54ca414b 100644 --- a/packages/backend/native-utils/crates/model/tests/common.rs +++ b/packages/backend/native-utils/crates/model/tests/common.rs @@ -7,7 +7,6 @@ use model::entity::{antenna, sea_orm_active_enums::AntennaSrcEnum, user}; use sea_orm::{ ActiveModelTrait, ActiveValue::Set, DatabaseConnection, DbErr, EntityTrait, TransactionTrait, }; -use serde_json::json; use std::env; use util::{ id::{create_id, init_id}, @@ -64,8 +63,16 @@ async fn setup_model(db: &DatabaseConnection) { user_id: Set(user_id.to_owned()), name: Set("Test Antenna".to_string()), src: Set(AntennaSrcEnum::All), - keywords: Set(json!([["foo", "bar"], ["foobar"]])), - exclude_keywords: Set(json!([["abc"], ["def", "ghi"]])), + keywords: Set(vec![ + vec!["foo".to_string(), "bar".to_string()], + vec!["foobar".to_string()], + ] + .into()), + exclude_keywords: Set(vec![ + vec!["abc".to_string()], + vec!["def".to_string(), "ghi".to_string()], + ] + .into()), with_file: Set(false), notify: Set(true), case_sensitive: Set(true), diff --git a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs index a7e490733a..73ddc65054 100644 --- a/packages/backend/native-utils/crates/model/tests/repository/antenna.rs +++ b/packages/backend/native-utils/crates/model/tests/repository/antenna.rs @@ -38,16 +38,18 @@ mod it_test { keywords: vec![ vec!["foo".to_string(), "bar".to_string()], vec!["foobar".to_string()] - ], + ] + .into(), exclude_keywords: vec![ vec!["abc".to_string()], vec!["def".to_string(), "ghi".to_string()] - ], + ] + .into(), src: schema::antenna::AntennaSrc::All, user_list_id: None, user_group_id: None, - users: vec![], - instances: vec![], + users: vec![].into(), + instances: vec![].into(), case_sensitive: true, notify: true, with_replies: false,