diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs index cfb7003e6640b0c1ef1060aa6d6782ac2d3dfb5c..d04b02ad71ce2f1805c7b63a683a28d834d545ad 100644 --- a/src/entities/vault_account.rs +++ b/src/entities/vault_account.rs @@ -2,18 +2,19 @@ use crate::commands::{cesium, vault}; use crate::runtime_config::AccountId; use crate::utils::GcliError; use anyhow::anyhow; +use sea_orm::entity::prelude::*; use sea_orm::prelude::async_trait::async_trait; use sea_orm::prelude::StringLen; use sea_orm::ActiveValue::Set; +use sea_orm::PaginatorTrait; use sea_orm::QueryFilter; +use sea_orm::TryGetError; use sea_orm::{ ActiveModelBehavior, ColumnTrait, DbErr, DeriveEntityModel, DerivePrimaryKey, EnumIter, Linked, ModelTrait, QueryOrder, RelationDef, RelationTrait, TryFromU64, }; use sea_orm::{ActiveModelTrait, ConnectionTrait, PrimaryKeyTrait}; use sea_orm::{DeriveActiveEnum, EntityTrait}; -use sea_orm::{FromJsonQueryResult, PaginatorTrait}; -use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Display; @@ -112,41 +113,58 @@ impl Display for Model { } } -/// Necessary to create a wrapper over AccountId32 to implement sea-orm traits -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult)] +/// Necessary to create a wrapper over AccountId to implement sea-orm traits +#[derive(Debug, Clone, PartialEq, Eq)] pub struct DbAccountId(pub AccountId); -impl FromStr for DbAccountId { - type Err = GcliError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - AccountId::from_str(s) - .map(DbAccountId) - .map_err(|_| GcliError::Input("Invalid AccountId format".to_string())) +/// All the next methods are necessary to support the proper mapping of the DbAccountId from/to String in DB and +/// to allow using it as primaryKey +impl sea_orm::sea_query::Nullable for DbAccountId { + fn null() -> Value { + Value::String(None) } } -impl Display for DbAccountId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl sea_orm::TryGetable for DbAccountId { + /// Had to really pay attention to return proper TryGetError type when value not present => TryGetError::Null + /// + /// as otherwise, when using `Option<DbAccountId>` with a None value it was crashing (when no "parent") + fn try_get_by<I: sea_orm::ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> { + let value: String = res + .try_get_by(idx) + .map_err(|e| TryGetError::Null(e.to_string()))?; + Ok(DbAccountId(AccountId::from_str(&value).map_err(|e| { + TryGetError::DbErr(DbErr::Custom(e.to_string())) + })?)) } } -impl From<AccountId> for DbAccountId { - fn from(account_id: AccountId) -> Self { - DbAccountId(account_id) +impl sea_orm::sea_query::ValueType for DbAccountId { + fn try_from(v: Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> { + match v { + Value::String(Some(value)) => Ok(DbAccountId( + AccountId::from_str(&value).map_err(|_| sea_orm::sea_query::ValueTypeErr)?, + )), + _ => Err(sea_orm::sea_query::ValueTypeErr), + } } -} -impl From<DbAccountId> for AccountId { - fn from(db_account_id: DbAccountId) -> Self { - db_account_id.0 + fn type_name() -> String { + stringify!(DbAccountId).to_owned() + } + + fn array_type() -> sea_orm::sea_query::ArrayType { + sea_orm::sea_query::ArrayType::String + } + + fn column_type() -> ColumnType { + ColumnType::String(StringLen::None) } } -impl From<String> for DbAccountId { - fn from(s: String) -> Self { - DbAccountId(AccountId::from_str(&s).expect("Invalid AccountId format")) +impl From<DbAccountId> for Value { + fn from(account_id: DbAccountId) -> Self { + Value::String(Some(Box::new(account_id.0.to_string()))) } } @@ -159,6 +177,40 @@ impl TryFromU64 for DbAccountId { } } +impl Display for DbAccountId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromStr for DbAccountId { + type Err = GcliError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(DbAccountId( + AccountId::from_str(s).map_err(|e| GcliError::Input(e.to_string()))?, + )) + } +} + +impl From<String> for DbAccountId { + fn from(s: String) -> Self { + DbAccountId(AccountId::from_str(&s).expect("Invalid AccountId format")) + } +} + +impl From<AccountId> for DbAccountId { + fn from(account_id: AccountId) -> Self { + DbAccountId(account_id) + } +} + +impl From<DbAccountId> for AccountId { + fn from(db_account_id: DbAccountId) -> Self { + db_account_id.0 + } +} + /// Didn't want to pollute the keys::CryptoScheme enum with sea-orm specific derivations /// /// created a separate enum for the database with conversions between the two