From e8da3aa99c21e3e93672d31c4d1d934adbdd7819 Mon Sep 17 00:00:00 2001
From: Nicolas80 <nicolas.pmail@protonmail.com>
Date: Tue, 11 Mar 2025 08:39:29 +0100
Subject: [PATCH 1/4] Added extra message when the DB parsing of DbAccountId
 fails, so we know for which string it failed.

---
 src/entities/vault_account.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs
index d04b02a..f2db84c 100644
--- a/src/entities/vault_account.rs
+++ b/src/entities/vault_account.rs
@@ -134,7 +134,10 @@ impl sea_orm::TryGetable for DbAccountId {
 			.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()))
+			TryGetError::DbErr(DbErr::Custom(format!(
+				"Cannot parse DbAccountId for string '{}' - error: {}",
+				&value, e
+			)))
 		})?))
 	}
 }
-- 
GitLab


From 54e82c1b7215d4700cfa723c3431511ef9293d85 Mon Sep 17 00:00:00 2001
From: Nicolas80 <nicolas.pmail@protonmail.com>
Date: Wed, 26 Mar 2025 10:31:16 +0100
Subject: [PATCH 2/4] * Adapted `impl FromStr for DbAccountId` so that it is
 the only one that does the conversion from &str to DbAccountId ** It provides
 error with the "raw" string that couldn't be parsed ** All other methods use
 that one now ** In order to be able to resolve the issue from !48; we now
 remove any surrounding double quotes from the string (if present) before
 parsing into a DbAccountId * Replaced `impl From<String> for DbAccountId`
 with `impl TryFrom<String> for DbAccountId` and adapted the code to use it. *
 Made sure `impl sea_orm::TryGetable for DbAccountId` also use the correct
 `DbAccountId::from_str` that will now provide the detailed error message

---
 src/commands/vault.rs         |  7 ++---
 src/entities/vault_account.rs | 48 ++++++++++++++++++++---------------
 2 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/src/commands/vault.rs b/src/commands/vault.rs
index 8d6de10..2f53bbf 100644
--- a/src/commands/vault.rs
+++ b/src/commands/vault.rs
@@ -729,7 +729,7 @@ where
 	println!();
 
 	let vault_account = if let Some(existing_vault_account) =
-		vault_account::find_by_id(db_tx, &DbAccountId::from(address_to_import.clone())).await?
+		vault_account::find_by_id(db_tx, &DbAccountId::try_from(address_to_import.clone())?).await?
 	{
 		if existing_vault_account.is_base_account() {
 			println!("You are trying to add {address_to_import} as a <Base> account while it already exists as a <Base> account.");
@@ -853,7 +853,8 @@ where
 	println!("Trying to create derivation with address '{derivation_address}'");
 	println!();
 	let vault_account = if let Some(existing_vault_account) =
-		vault_account::find_by_id(db_tx, &DbAccountId::from(derivation_address.clone())).await?
+		vault_account::find_by_id(db_tx, &DbAccountId::try_from(derivation_address.clone())?)
+			.await?
 	{
 		// Existing account
 		println!("You are trying to derive '{derivation_path}' from parent '{parent_address}'");
@@ -922,7 +923,7 @@ where
 				// Since links are made based on address / parent(address) we can just edit the existing entry and it should be fine
 				let mut vault_account: ActiveModel = existing_vault_account.into();
 				vault_account.path = Set(Some(derivation_path.clone()));
-				vault_account.parent = Set(Some(DbAccountId::from(parent_address.clone())));
+				vault_account.parent = Set(Some(DbAccountId::try_from(parent_address.clone())?));
 				vault_account.crypto_scheme = Set(None);
 				vault_account.encrypted_suri = Set(None);
 				vault_account.name = Set(name.clone());
diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs
index f2db84c..4c219e6 100644
--- a/src/entities/vault_account.rs
+++ b/src/entities/vault_account.rs
@@ -133,21 +133,16 @@ impl sea_orm::TryGetable for DbAccountId {
 		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(format!(
-				"Cannot parse DbAccountId for string '{}' - error: {}",
-				&value, e
-			)))
-		})?))
+		DbAccountId::from_str(&value).map_err(|e| TryGetError::DbErr(DbErr::Custom(e.to_string())))
 	}
 }
 
 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)?,
-			)),
+			Value::String(Some(value)) => {
+				Ok(DbAccountId::from_str(&value).map_err(|_| sea_orm::sea_query::ValueTypeErr)?)
+			}
 			_ => Err(sea_orm::sea_query::ValueTypeErr),
 		}
 	}
@@ -186,19 +181,32 @@ impl Display for DbAccountId {
 	}
 }
 
-impl FromStr for DbAccountId {
-	type Err = GcliError;
+impl TryFrom<String> for DbAccountId {
+	type Error = GcliError;
 
-	fn from_str(s: &str) -> Result<Self, Self::Err> {
-		Ok(DbAccountId(
-			AccountId::from_str(s).map_err(|e| GcliError::Input(e.to_string()))?,
-		))
+	fn try_from(value: String) -> Result<Self, Self::Error> {
+		DbAccountId::from_str(&value)
 	}
 }
 
-impl From<String> for DbAccountId {
-	fn from(s: String) -> Self {
-		DbAccountId(AccountId::from_str(&s).expect("Invalid AccountId format"))
+/// This one is used by the other methods converting from String and does potential extra cleanup of the string before parsing.
+///
+/// Due to a hard to reproduce issue (!48) we added trim of double quotes (") at start and end of the string.
+impl FromStr for DbAccountId {
+	type Err = GcliError;
+
+	fn from_str(s: &str) -> Result<Self, Self::Err> {
+		// Remove surrounding double quotes if present
+		let cleaned_value = s.trim_matches('"');
+
+		Ok(DbAccountId(AccountId::from_str(cleaned_value).map_err(
+			|e| {
+				GcliError::Input(format!(
+					"Cannot parse DbAccountId for raw string '{}' - error: {}",
+					s, e
+				))
+			},
+		)?))
 	}
 }
 
@@ -924,12 +932,12 @@ where
 		}
 		None => {
 			let vault_account = ActiveModel {
-				address: Set(address.to_string().into()),
+				address: Set(address.to_string().try_into()?),
 				name: Set(name.cloned()),
 				path: Set(Some(derivation_path.to_string())),
 				crypto_scheme: Set(None),
 				encrypted_suri: Set(None),
-				parent: Set(Some(parent_address.to_string().into())),
+				parent: Set(Some(parent_address.to_string().try_into()?)),
 			};
 			vault_account.insert(db).await?
 		}
-- 
GitLab


From 2cd0a861751fe9336ad03e847cc43dedf593e0eb Mon Sep 17 00:00:00 2001
From: Nicolas80 <nicolas.pmail@protonmail.com>
Date: Wed, 26 Mar 2025 10:50:54 +0100
Subject: [PATCH 3/4] * Kind of ugly; but needed to adapt fn
 find_direct_children_accounts to also match lines that have extra double
 quotes inside the parent column ** For that; since it seems sea-orm does the
 `eq` part on string values; the only way I could find is to allow any of
 those checks *** original "parent" eq address as DbAccountId (sea-orm
 converts address' DbAccountId to a clean string that doesn't have the extra
 double quotes) *** extra "parent" eq
 `format!("\"{}\"",current_account.address.to_string())` for the cases where
 the DB got incorrect values

---
 src/entities/vault_account.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs
index 4c219e6..80586cf 100644
--- a/src/entities/vault_account.rs
+++ b/src/entities/vault_account.rs
@@ -6,7 +6,6 @@ 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::{
@@ -14,6 +13,7 @@ use sea_orm::{
 	ModelTrait, QueryOrder, RelationDef, RelationTrait, TryFromU64,
 };
 use sea_orm::{ActiveModelTrait, ConnectionTrait, PrimaryKeyTrait};
+use sea_orm::{Condition, PaginatorTrait};
 use sea_orm::{DeriveActiveEnum, EntityTrait};
 use std::cell::RefCell;
 use std::collections::HashMap;
@@ -768,6 +768,9 @@ where
 	Ok(Some(base_parent_account))
 }
 
+/// Fetches all the children accounts of current_account
+///
+/// Due to a hard to reproduce issue (!48) had to adapt the filter on Parent to also match if the Parent value has those extra double quotes around the value
 async fn find_direct_children_accounts<C>(
 	db: &C,
 	current_account: &Model,
@@ -776,7 +779,11 @@ where
 	C: ConnectionTrait,
 {
 	Entity::find()
-		.filter(Column::Parent.eq(current_account.address.clone()))
+		.filter(
+			Condition::any()
+				.add(Column::Parent.eq(current_account.address.clone()))
+				.add(Column::Parent.eq(format!("\"{}\"",current_account.address.to_string()))),
+		)
 		.order_by_asc(Column::Address)
 		.all(db)
 		.await
-- 
GitLab


From 5924a73e25a251385eeae430724ea13b7dd49b5c Mon Sep 17 00:00:00 2001
From: Nicolas80 <nicolas.pmail@protonmail.com>
Date: Wed, 26 Mar 2025 13:26:31 +0100
Subject: [PATCH 4/4] * Added `debug!` log inside `impl From<DbAccountId> for
 Value` used to serialize DbAccountId into the String value for the db ** Can
 be seen when adding `RUST_LOG=debug ` before the `gcli` command * Small fix
 for clippy remark

---
 src/entities/vault_account.rs | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/entities/vault_account.rs b/src/entities/vault_account.rs
index 80586cf..ec81c65 100644
--- a/src/entities/vault_account.rs
+++ b/src/entities/vault_account.rs
@@ -2,6 +2,7 @@ use crate::commands::{cesium, vault};
 use crate::runtime_config::AccountId;
 use crate::utils::GcliError;
 use anyhow::anyhow;
+use log::debug;
 use sea_orm::entity::prelude::*;
 use sea_orm::prelude::async_trait::async_trait;
 use sea_orm::prelude::StringLen;
@@ -162,7 +163,12 @@ impl sea_orm::sea_query::ValueType for DbAccountId {
 
 impl From<DbAccountId> for Value {
 	fn from(account_id: DbAccountId) -> Self {
-		Value::String(Some(Box::new(account_id.0.to_string())))
+		let account_id_string = account_id.0.to_string();
+		debug!(
+			"DB converting DbAccountId to string:'{}'",
+			account_id_string
+		);
+		Value::String(Some(Box::new(account_id_string)))
 	}
 }
 
@@ -782,7 +788,7 @@ where
 		.filter(
 			Condition::any()
 				.add(Column::Parent.eq(current_account.address.clone()))
-				.add(Column::Parent.eq(format!("\"{}\"",current_account.address.to_string()))),
+				.add(Column::Parent.eq(format!("\"{}\"", current_account.address))),
 		)
 		.order_by_asc(Column::Address)
 		.all(db)
-- 
GitLab