-
Notifications
You must be signed in to change notification settings - Fork 1
Add new query for fetching all metaboard addresses #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,10 @@ | ||
| use crate::cynic_client::{CynicClient, CynicClientError}; | ||
| use crate::types::metas::*; | ||
| use alloy::primitives::hex::{decode, encode, FromHexError}; | ||
| use alloy::primitives::{ | ||
| hex::{decode, encode, FromHexError}, | ||
| Address, | ||
| }; | ||
| use core::str::FromStr; | ||
| use reqwest::Url; | ||
| use thiserror::Error; | ||
|
|
||
|
|
@@ -26,6 +30,17 @@ pub enum MetaboardSubgraphClientError { | |
| #[source] | ||
| source: FromHexError, | ||
| }, | ||
| #[error("Error parsing metaboard address {address}: {source}")] | ||
| AddressParseError { | ||
| address: String, | ||
| #[source] | ||
| source: <Address as FromStr>::Err, | ||
| }, | ||
| #[error("Request error fetching metaboard addresses: {source}")] | ||
| RequestErrorMetaBoards { | ||
| #[source] | ||
| source: CynicClientError, | ||
| }, | ||
| } | ||
|
|
||
| pub struct MetaboardSubgraphClient { | ||
|
|
@@ -111,6 +126,35 @@ impl MetaboardSubgraphClient { | |
|
|
||
| Ok(meta_bytes) | ||
| } | ||
|
|
||
| /// Fetch MetaBoard contract addresses from the subgraph. | ||
| pub async fn get_metaboard_addresses( | ||
| &self, | ||
| first: Option<i32>, | ||
| skip: Option<i32>, | ||
| ) -> Result<Vec<Address>, MetaboardSubgraphClientError> { | ||
| let data = | ||
| self.query::<MetaBoardAddresses, MetaBoardAddressesVariables>( | ||
| MetaBoardAddressesVariables { first, skip }, | ||
| ) | ||
| .await | ||
| .map_err(|e| MetaboardSubgraphClientError::RequestErrorMetaBoards { source: e })?; | ||
|
|
||
| let mut addresses = Vec::with_capacity(data.meta_boards.len()); | ||
| for board in data.meta_boards { | ||
| let address_hex = board.address.0; | ||
| let address = Address::from_str(&address_hex).map_err(|e| { | ||
| MetaboardSubgraphClientError::AddressParseError { | ||
| address: address_hex.clone(), | ||
| source: e, | ||
| } | ||
| })?; | ||
|
|
||
| addresses.push(address); | ||
| } | ||
|
|
||
| Ok(addresses) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
|
|
@@ -289,4 +333,69 @@ mod tests { | |
| _ => panic!("Unexpected result: {:?}", result), | ||
| } | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_get_metaboard_addresses_success() { | ||
| let server = MockServer::start_async().await; | ||
| let url = Url::parse(&server.url("/")).unwrap(); | ||
|
|
||
| server.mock(|when, then| { | ||
| when.method(POST).path("/").body_contains("metaBoards"); | ||
| then.status(200).json_body_obj(&{ | ||
| serde_json::json!({ | ||
| "data": { | ||
| "metaBoards": [ | ||
| { | ||
| "address": "0x0000000000000000000000000000000000000001", | ||
| }, | ||
| { | ||
| "address": "0x0000000000000000000000000000000000000002", | ||
| } | ||
| ] | ||
| } | ||
| }) | ||
| }); | ||
| }); | ||
|
|
||
| let client = MetaboardSubgraphClient::new(url); | ||
|
|
||
| let result = client | ||
| .get_metaboard_addresses(Some(10), Some(0)) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| assert_eq!(result.len(), 2); | ||
|
|
||
| assert_eq!( | ||
| result[0], | ||
| Address::from_str("0x0000000000000000000000000000000000000001").unwrap() | ||
| ); | ||
| assert_eq!( | ||
| result[1], | ||
| Address::from_str("0x0000000000000000000000000000000000000002").unwrap() | ||
| ); | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_get_metaboard_addresses_empty() { | ||
| let server = MockServer::start_async().await; | ||
| let url = Url::parse(&server.url("/")).unwrap(); | ||
|
|
||
| server.mock(|when, then| { | ||
| when.method(POST).path("/").body_contains("metaBoards"); | ||
| then.status(200).json_body_obj(&{ | ||
| serde_json::json!({ | ||
| "data": { | ||
| "metaBoards": [] | ||
| } | ||
| }) | ||
| }); | ||
| }); | ||
|
|
||
| let client = MetaboardSubgraphClient::new(url); | ||
|
|
||
| let result = client.get_metaboard_addresses(Some(5), None).await.unwrap(); | ||
|
|
||
| assert!(result.is_empty()); | ||
| } | ||
|
Comment on lines
+337
to
+400
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial LGTM! Consider adding error path tests. The success and empty result tests are well-structured and follow the existing test patterns. However, consider adding tests for error paths to improve coverage:
Example test structure: #[tokio::test]
async fn test_get_metaboard_addresses_invalid_address() {
let server = MockServer::start_async().await;
let url = Url::parse(&server.url("/")).unwrap();
server.mock(|when, then| {
when.method(POST).path("/").body_contains("metaBoards");
then.status(200).json_body_obj(&{
serde_json::json!({
"data": {
"metaBoards": [
{
"address": "invalid_address",
}
]
}
})
});
});
let client = MetaboardSubgraphClient::new(url);
let result = client.get_metaboard_addresses(None, None).await;
assert!(result.is_err());
match result {
Err(MetaboardSubgraphClientError::AddressParseError { .. }) => (),
_ => panic!("Expected AddressParseError, got: {:?}", result),
}
}🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is fine as contracts are indexed in sg. we are getting proper addresses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @findolor, understood! Since the subgraph ensures valid addresses are indexed, the existing success and empty result tests provide sufficient coverage. Thank you for clarifying! 👍 🧠 Learnings used |
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Verify empty result handling is intentional.
The implementation correctly parses addresses and handles errors. However, there's an inconsistency with the existing methods:
get_metabytes_by_hashandget_metabytes_by_subjectreturnMetaboardSubgraphClientError::Emptywhen no results are foundVec<Address>when no results are foundConfirm whether returning an empty vector for zero MetaBoards is the intended behavior, or if it should follow the existing pattern and return an error.
Optional: Consider validating pagination parameters.
The pagination parameters
firstandskipare passed directly to the subgraph without validation. While the subgraph will likely handle invalid values, client-side validation (e.g., rejecting negative values) could provide clearer error messages.🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an empty array is also fine. this means nothing is found
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@findolor, understood! I've noted that returning an empty array is the intended behavior for
get_metaboard_addresses. The method will remain as-is./| |_
( === _)
`-.-'
✏️ Learnings added