Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

support querying multiple subgraph's features in single query #6142

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

Open
shiyasmohd wants to merge 1 commit into master
base: master
Choose a base branch
Loading
from shiyasmohd/subgraph-features-arr
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions graph/src/data/subgraph/mod.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ impl IntoValue for DeploymentFeatures {
fn into_value(self) -> r::Value {
object! {
__typename: "SubgraphFeatures",
subgraph: self.id,
specVersion: self.spec_version,
apiVersion: self.api_version,
features: self.features,
Expand Down
73 changes: 47 additions & 26 deletions server/index-node/src/resolver.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashSet};
use std::convert::TryInto;

use graph::data::query::Trace;
Expand Down Expand Up @@ -565,37 +565,54 @@ impl<S: Store> IndexNodeResolver<S> {
field: &a::Field,
) -> Result<r::Value, QueryExecutionError> {
// We can safely unwrap because the argument is non-nullable and has been validated.
let subgraph_id = field.get_required::<String>("subgraphId").unwrap();
let subgraph_ids: HashSet<String> = field
.get_required::<Vec<String>>("subgraphs")
.unwrap()
.into_iter()
.collect();

// Try to build a deployment hash with the input string
let deployment_hash = DeploymentHash::new(subgraph_id).map_err(|invalid_qm_hash| {
QueryExecutionError::SubgraphDeploymentIdError(invalid_qm_hash)
})?;
if subgraph_ids.is_empty() {
return Ok(r::Value::List(Vec::new()));
}

let subgraph_store = self.store.subgraph_store();
let features = match subgraph_store.subgraph_features(&deployment_hash).await? {
Some(features) => {
let mut deployment_features = features.clone();
let features = &mut deployment_features.features;
let mut all_features = vec![];

if deployment_features.has_declared_calls {
features.push("declaredEthCalls".to_string());
}
if deployment_features.has_aggregations {
features.push("aggregations".to_string());
for subgraph_id in subgraph_ids {
let deployment_hash = match DeploymentHash::new(subgraph_id) {
Ok(hash) => hash,
Err(_) => {
continue;
}
if !deployment_features.immutable_entities.is_empty() {
features.push("immutableEntities".to_string());
}
if deployment_features.has_bytes_as_ids {
features.push("bytesAsIds".to_string());
};

// Fetch features from store or IPFS
let features = match subgraph_store.subgraph_features(&deployment_hash).await? {
Some(features) => {
let mut deployment_features = features.clone();
let features = &mut deployment_features.features;

if deployment_features.has_declared_calls {
features.push("declaredEthCalls".to_string());
}
if deployment_features.has_aggregations {
features.push("aggregations".to_string());
}
if !deployment_features.immutable_entities.is_empty() {
features.push("immutableEntities".to_string());
}
if deployment_features.has_bytes_as_ids {
features.push("bytesAsIds".to_string());
}
deployment_features
}
deployment_features
}
None => self.get_features_from_ipfs(&deployment_hash).await?,
};
None => self.get_features_from_ipfs(&deployment_hash).await?,
};

Ok(features.into_value())
all_features.push(features.into_value());
}

Ok(r::Value::List(all_features))
}

fn resolve_api_versions(&self, _field: &a::Field) -> Result<r::Value, QueryExecutionError> {
Expand Down Expand Up @@ -817,6 +834,11 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
self.resolve_public_proofs_of_indexing(field).await
}

// The top-level `subgraphFeatures` field
(None, "SubgraphFeatures", "subgraphFeatures") => {
self.resolve_subgraph_features(field).await
}

// Resolve fields of `Object` values (e.g. the `chains` field of `ChainIndexingStatus`)
(value, _, _) => Ok(value.unwrap_or(r::Value::Null)),
}
Expand All @@ -837,7 +859,6 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
(None, "indexingStatusForPendingVersion") => {
self.resolve_indexing_status_for_version(field, false)
}
(None, "subgraphFeatures") => self.resolve_subgraph_features(field).await,
(None, "entityChangesInBlock") => self.resolve_entity_changes_in_block(field),
// The top-level `subgraphVersions` field
(None, "apiVersions") => self.resolve_api_versions(field),
Expand Down
3 changes: 2 additions & 1 deletion server/index-node/src/schema.graphql
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Query {
publicProofsOfIndexing(
requests: [PublicProofOfIndexingRequest!]!
): [PublicProofOfIndexingResult!]!
subgraphFeatures(subgraphId: String!): SubgraphFeatures!
subgraphFeatures(subgraphs: [String!]!): [SubgraphFeatures!]!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change - existing queries for subgraph features will break after this change. I am not sure how big a deal that is and how many people are using this, but it could be a problem

entityChangesInBlock(subgraphId: String!, blockNumber: Int!): EntityChanges!
blockData(network: String!, blockHash: Bytes!): JSONObject
blockHashFromNumber(network: String!, blockNumber: Int!): Bytes
Expand Down Expand Up @@ -148,6 +148,7 @@ type CachedEthereumCall {
}

type SubgraphFeatures {
subgraph: String!
apiVersion: String
specVersion: String!
features: [Feature!]!
Expand Down
47 changes: 42 additions & 5 deletions tests/tests/integration_tests.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,8 @@ pub async fn test_block_handlers(ctx: TestContext) -> anyhow::Result<()> {
// test subgraphFeatures endpoint returns handlers correctly
let subgraph_features = Subgraph::query_with_vars(
"query GetSubgraphFeatures($deployment: String!) {
subgraphFeatures(subgraphId: $deployment) {
subgraphFeatures(subgraphs: [$deployment]) {
subgraph
specVersion
apiVersion
features
Expand All @@ -546,7 +547,23 @@ pub async fn test_block_handlers(ctx: TestContext) -> anyhow::Result<()> {
json!({ "deployment": subgraph.deployment }),
)
.await?;
let handlers = &subgraph_features["data"]["subgraphFeatures"]["handlers"];
// The response is now an array, get the first element
let features_array = &subgraph_features["data"]["subgraphFeatures"];
assert!(
features_array.is_array(),
"subgraphFeatures must return an array"
);
assert_eq!(
features_array.as_array().unwrap().len(),
1,
"Expected exactly one subgraph feature set"
);
let subgraph_feature = &features_array[0];
assert_eq!(
subgraph_feature["subgraph"], subgraph.deployment,
"Subgraph ID should match the deployment"
);
let handlers = &subgraph_feature["handlers"];
assert!(
handlers.is_array(),
"subgraphFeatures.handlers must be an array"
Expand Down Expand Up @@ -762,7 +779,8 @@ async fn test_non_fatal_errors(ctx: TestContext) -> anyhow::Result<()> {
assert!(!subgraph.healthy);

let query = "query GetSubgraphFeatures($deployment: String!) {
subgraphFeatures(subgraphId: $deployment) {
subgraphFeatures(subgraphs: [$deployment]) {
subgraph
specVersion
apiVersion
features
Expand All @@ -774,16 +792,35 @@ async fn test_non_fatal_errors(ctx: TestContext) -> anyhow::Result<()> {

let resp =
Subgraph::query_with_vars(query, json!({ "deployment" : subgraph.deployment })).await?;
let subgraph_features = &resp["data"]["subgraphFeatures"];

// The response is now an array, get the first element
let features_array = &resp["data"]["subgraphFeatures"];
assert!(
features_array.is_array(),
"subgraphFeatures must return an array"
);
assert_eq!(
features_array.as_array().unwrap().len(),
1,
"Expected exactly one subgraph feature set"
);

let subgraph_feature = &features_array[0];
assert_eq!(
subgraph_feature["subgraph"], subgraph.deployment,
"Subgraph ID should match the deployment"
);

let exp = json!({
"subgraph": subgraph.deployment,
"specVersion": "0.0.4",
"apiVersion": "0.0.6",
"features": ["nonFatalErrors"],
"dataSources": ["ethereum/contract"],
"handlers": ["block"],
"network": "test",
});
assert_eq!(&exp, subgraph_features);
assert_eq!(&exp, subgraph_feature);

let resp = subgraph
.query("{ foos(orderBy: id, subgraphError: allow) { id } }")
Expand Down

AltStyle によって変換されたページ (->オリジナル) /