-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Introduce client api with nextEntryArgs stub * Implement current nextEntryArgs RPC method using graphql * Fix basic graphql endpoint test * Add tests * Update changelog * Handle errors * Clean up * Refactor for storage provider * Revert changelog style change * Move request/response structs to graphql client module * Adapt EntryArgsResponse implementation to GraphQL * Recover old file structure for now * Improve test * Switch back branch * Clarify test scope * Handle serialisation in EntryArgsResponse impl * Implement deserialisation * Implement serialisation * Rearrange file Co-authored-by: Sam Andreae <contact@samandreae.com>
- Loading branch information
Showing
15 changed files
with
327 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
/// A specialized result type for the storage provider. | ||
pub type StorageProviderResult<T> = anyhow::Result<T, Box<dyn std::error::Error + Sync + Send>>; | ||
pub type StorageProviderResult<T> = anyhow::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
// SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
use async_graphql::{Context, Error, Object, Result}; | ||
use p2panda_rs::document::DocumentId; | ||
use p2panda_rs::identity::Author; | ||
use p2panda_rs::storage_provider::traits::StorageProvider; | ||
|
||
use crate::db::provider::SqlStorage; | ||
use crate::db::Pool; | ||
|
||
use super::{EntryArgsRequest, EntryArgsResponse}; | ||
|
||
#[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; | ||
|
||
#[Object] | ||
impl ClientRoot { | ||
/// Return required arguments for publishing the next entry. | ||
async fn next_entry_args( | ||
&self, | ||
ctx: &Context<'_>, | ||
#[graphql( | ||
name = "publicKey", | ||
desc = "Public key that will publish using the returned entry arguments" | ||
)] | ||
public_key_param: String, | ||
#[graphql( | ||
name = "documentId", | ||
desc = "Document id to which the entry's operation will apply" | ||
)] | ||
document_id_param: Option<String>, | ||
) -> Result<EntryArgsResponse> { | ||
// Parse and validate parameters | ||
let document_id = match document_id_param { | ||
Some(val) => Some(val.parse::<DocumentId>()?), | ||
None => None, | ||
}; | ||
let args = EntryArgsRequest { | ||
author: Author::new(&public_key_param)?, | ||
document: document_id, | ||
}; | ||
|
||
// Prepare database connection | ||
let pool = ctx.data::<Pool>()?; | ||
let provider = SqlStorage { | ||
pool: pool.to_owned(), | ||
}; | ||
|
||
provider | ||
.get_entry_args(&args) | ||
.await | ||
.map_err(|err| Error::from(err)) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use async_graphql::{value, Response}; | ||
use p2panda_rs::entry::{LogId, SeqNum}; | ||
use serde_json::json; | ||
|
||
use crate::config::Configuration; | ||
use crate::context::Context; | ||
use crate::graphql::client::EntryArgsResponse; | ||
use crate::server::build_server; | ||
use crate::test_helpers::{initialize_db, TestClient}; | ||
|
||
#[tokio::test] | ||
async fn next_entry_args_valid_query() { | ||
let pool = initialize_db().await; | ||
let context = Context::new(pool.clone(), Configuration::default()); | ||
let client = TestClient::new(build_server(context)); | ||
|
||
// Selected fields need to be alphabetically sorted because that's what the `json` macro | ||
// that is used in the assert below produces. | ||
let response = client | ||
.post("/graphql") | ||
.json(&json!({ | ||
"query": r#"{ | ||
nextEntryArgs( | ||
publicKey: "8b52ae153142288402382fd6d9619e018978e015e6bc372b1b0c7bd40c6a240a" | ||
) { | ||
logId, | ||
seqNum, | ||
backlink, | ||
skiplink | ||
} | ||
}"#, | ||
})) | ||
.send() | ||
.await | ||
// .json::<GQLResponse<EntryArgsGQLResponse>>() | ||
.json::<Response>() | ||
.await; | ||
|
||
let expected_entry_args = EntryArgsResponse { | ||
log_id: LogId::new(1), | ||
seq_num: SeqNum::new(1).unwrap(), | ||
backlink: None, | ||
skiplink: None, | ||
}; | ||
let received_entry_args: EntryArgsResponse = match response.data { | ||
async_graphql::Value::Object(result_outer) => { | ||
async_graphql::from_value(result_outer.get("nextEntryArgs").unwrap().to_owned()) | ||
.unwrap() | ||
} | ||
_ => panic!("Expected return value to be an object"), | ||
}; | ||
|
||
assert_eq!(received_entry_args, expected_entry_args); | ||
} | ||
|
||
#[tokio::test] | ||
async fn next_entry_args_error_response() { | ||
let pool = initialize_db().await; | ||
let context = Context::new(pool.clone(), Configuration::default()); | ||
let client = TestClient::new(build_server(context)); | ||
|
||
// Selected fields need to be alphabetically sorted because that's what the `json` macro | ||
// that is used in the assert below produces. | ||
|
||
let response = client | ||
.post("/graphql") | ||
.json(&json!({ | ||
"query": r#"{ | ||
nextEntryArgs(publicKey: "nope") { | ||
logId | ||
} | ||
}"#, | ||
})) | ||
.send() | ||
.await; | ||
|
||
let response: Response = response.json().await; | ||
assert_eq!( | ||
response.errors[0].message, | ||
"invalid hex encoding in author string" | ||
) | ||
} | ||
} |
Oops, something went wrong.