diff --git a/aquadoggo/src/graphql/client/root.rs b/aquadoggo/src/graphql/client/root.rs index 3cd8fb9b8..7bebd9ec4 100644 --- a/aquadoggo/src/graphql/client/root.rs +++ b/aquadoggo/src/graphql/client/root.rs @@ -2,13 +2,16 @@ use async_graphql::{Context, Error, Object, Result, SimpleObject}; use bamboo_rs_core_ed25519_yasmf::entry::is_lipmaa_required as is_skiplink_required; -use p2panda_rs::entry::SeqNum; +use p2panda_rs::document::DocumentId; use p2panda_rs::hash::Hash; use p2panda_rs::identity::Author; +use p2panda_rs::storage_provider::traits::StorageProvider; -use crate::db::models::{Entry, Log}; +use crate::db::provider::SqlStorage; use crate::db::Pool; +use crate::rpc::{EntryArgsRequest, EntryArgsResponse}; +// #[derive(SimpleObject)] pub struct EntryArgs { pub log_id: String, @@ -17,6 +20,17 @@ pub struct EntryArgs { pub skiplink: Option, } +impl From for EntryArgs { + fn from(value: EntryArgsResponse) -> Self { + EntryArgs { + log_id: value.log_id.as_u64().to_string(), + seq_num: value.seq_num.as_u64().to_string(), + backlink: value.entry_hash_backlink.map(|hash| hash.to_string()), + skiplink: value.entry_hash_skiplink.map(|hash| hash.to_string()), + } + } +} + #[derive(Default, Debug, Copy, Clone)] /// The GraphQL root for the client api that p2panda clients can use to connect to a node. pub struct ClientRoot; @@ -38,69 +52,30 @@ impl ClientRoot { )] document_id_param: Option, ) -> Result { - let public_key = Author::new(&public_key_param)?; + // Parse and validate parameters let document_id = match document_id_param { - Some(value) => Some(Hash::new(&value)?), + Some(val) => Some(val.parse::()?), None => None, }; + let args = EntryArgsRequest { + author: Author::new(&public_key_param)?, + document: document_id, + }; - // Get database connection pool + // Prepare database connection let pool = ctx.data::().map_err(|err| Error::from(err))?; + let provider = SqlStorage { + pool: pool.to_owned(), + }; - // Determine log_id for this document. If this is the very first operation in the document - // graph, the `document` value is None and we will return the next free log id - let log_id = Log::find_document_log_id(&pool, &public_key, document_id.as_ref()).await?; - - // Determine backlink and skiplink hashes for the next entry. To do this we need the latest - // entry in this log - let entry_latest = Entry::latest(&pool, &public_key, &log_id).await?; - - match entry_latest { - // An entry was found which serves as the backlink for the upcoming entry - Some(mut entry_backlink) => { - // Determine skiplink ("lipmaa"-link) entry in this log - let skiplink = determine_skiplink(pool.clone(), &entry_backlink).await?; - - Ok(EntryArgs { - log_id: log_id.as_u64().to_string(), - seq_num: entry_backlink.seq_num.next().unwrap().as_u64().to_string(), - backlink: Some(entry_backlink.entry_hash.as_str().into()), - skiplink: skiplink.map(|h| h.as_str().into()), - }) - } - // No entry was given yet, we can assume this is the beginning of the log - None => Ok(EntryArgs { - log_id: log_id.as_u64().to_string(), - seq_num: SeqNum::default().as_u64().to_string(), - backlink: None, - skiplink: None, - }), + match provider.get_entry_args(&args).await { + Ok(entry_args) => Ok(entry_args.into()), + Err(_) => Err(Error::new("Graphql gone wrong")), + // Err(err) => Err(Error::from(err)), } } } -/// Determine skiplink entry hash for entry in this log, return `None` when no skiplink is -/// required for the next entry. -pub async fn determine_skiplink(pool: Pool, entry: &Entry) -> Result> { - let next_seq_num = entry.seq_num.clone().next().unwrap(); - - // Unwrap as we know that an skiplink exists as soon as previous entry is given - let skiplink_seq_num = next_seq_num.skiplink_seq_num().unwrap(); - - // Check if skiplink is required and return hash if so - let entry_skiplink_hash = if is_skiplink_required(next_seq_num.as_u64()) { - let skiplink_entry = - Entry::at_seq_num(&pool, &entry.author, &entry.log_id, &skiplink_seq_num) - .await? - .unwrap(); - Some(skiplink_entry.entry_hash) - } else { - None - }; - - Ok(entry_skiplink_hash) -} - #[cfg(test)] mod tests { use serde_json::json;